From ffab5675f1c5da8aaad018a8ecb72432a298b647 Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Thu, 2 Feb 2023 15:30:16 +0530 Subject: [PATCH 01/21] v1 --- .../resource_ibm_is_instance_boot_volume.go | 954 ++++++++++++++++++ ...source_ibm_is_instance_boot_volume_test.go | 550 ++++++++++ 2 files changed, 1504 insertions(+) create mode 100644 ibm/service/vpc/resource_ibm_is_instance_boot_volume.go create mode 100644 ibm/service/vpc/resource_ibm_is_instance_boot_volume_test.go diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go new file mode 100644 index 0000000000..204df56984 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go @@ -0,0 +1,954 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc + +import ( + "context" + "fmt" + "log" + "os" + "strings" + "time" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const () + +func ResourceIBMISInstanceBootVolume() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMISInstanceBootVolumeCreate, + Read: resourceIBMISInstanceBootVolumeRead, + Update: resourceIBMISInstanceBootVolumeUpdate, + Delete: resourceIBMISInstanceBootVolumeDelete, + Exists: resourceIBMISInstanceBootVolumeExists, + Importer: &schema.ResourceImporter{}, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceTagsCustomizeDiff(diff) + }, + ), + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceVolumeValidate(diff) + }), + customdiff.Sequence( + func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + return flex.ResourceValidateAccessTags(diff, v) + }), + ), + + Schema: map[string]*schema.Schema{ + + isVolumeName: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", isVolumeName), + Description: "Volume name", + }, + + isVolumeProfileName: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", isVolumeProfileName), + Description: "Volume profile name", + }, + + isVolumeZone: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Zone name", + }, + + isVolumeEncryptionKey: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Volume encryption key info", + }, + + isVolumeEncryptionType: { + Type: schema.TypeString, + Computed: true, + Description: "Volume encryption type info", + }, + + isVolumeCapacity: { + Type: schema.TypeInt, + Optional: true, + 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, + Computed: true, + ForceNew: true, + Description: "Resource group name", + }, + isVolumeIops: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_volume", isVolumeIops), + Description: "IOPS value for the Volume", + }, + isVolumeCrn: { + Type: schema.TypeString, + Computed: true, + Description: "CRN value for the volume instance", + }, + isVolumeStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Volume status", + }, + + isVolumeStatusReasons: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + isVolumeStatusReasonsCode: { + Type: schema.TypeString, + Computed: true, + Description: "A snake case string succinctly identifying the status reason", + }, + + isVolumeStatusReasonsMessage: { + Type: schema.TypeString, + Computed: true, + Description: "An explanation of the status reason", + }, + + isVolumeStatusReasonsMoreInfo: { + Type: schema.TypeString, + 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.", + }, + isVolumeDeleteAllSnapshots: { + Type: schema.TypeBool, + Optional: true, + Description: "Deletes all snapshots created from this volume", + }, + isVolumeTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_volume", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "UserTags for the volume instance", + }, + isVolumeAccessTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_volume", "accesstag")}, + Set: flex.ResourceIBMVPCHash, + Description: "Access management tags for the volume instance", + }, + + flex.ResourceControllerURL: { + Type: schema.TypeString, + Computed: true, + Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", + }, + + flex.ResourceName: { + Type: schema.TypeString, + Computed: true, + Description: "The name of the resource", + }, + + flex.ResourceCRN: { + Type: schema.TypeString, + Computed: true, + Description: "The crn of the resource", + }, + + flex.ResourceStatus: { + Type: schema.TypeString, + Computed: true, + Description: "The status of the resource", + }, + + flex.ResourceGroupName: { + Type: schema.TypeString, + Computed: true, + Description: "The resource group name in which resource is provisioned", + }, + + isVolumeBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum bandwidth (in megabits per second) for the volume", + }, + }, + } +} + +func ResourceIBMISInstanceBootVolumeValidator() *validate.ResourceValidator { + + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isVolumeName, + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, + MinValueLength: 1, + MaxValueLength: 63}) + + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "tags", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[A-Za-z0-9:_ .-]+$`, + MinValueLength: 1, + MaxValueLength: 128}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isVolumeProfileName, + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "general-purpose, 5iops-tier, 10iops-tier, custom", + }) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isVolumeCapacity, + ValidateFunctionIdentifier: validate.IntBetween, + 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, + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + MinValue: "100", + MaxValue: "48000"}) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "accesstag", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([A-Za-z0-9_.-]|[A-Za-z0-9_.-][A-Za-z0-9_ .-]*[A-Za-z0-9_.-]):([A-Za-z0-9_.-]|[A-Za-z0-9_.-][A-Za-z0-9_ .-]*[A-Za-z0-9_.-])$`, + MinValueLength: 1, + MaxValueLength: 128}) + + ibmISVolumeResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_volume", Schema: validateSchema} + return &ibmISVolumeResourceValidator +} + +func resourceIBMISInstanceBootVolumeCreate(d *schema.ResourceData, meta interface{}) error { + + volName := d.Get(isVolumeName).(string) + profile := d.Get(isVolumeProfileName).(string) + zone := d.Get(isVolumeZone).(string) + + err := instanceBootVolCreate(d, meta, volName, profile, zone) + if err != nil { + return err + } + + return resourceIBMISVolumeRead(d, meta) +} + +func instanceBootVolCreate(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, + Zone: &vpcv1.ZoneIdentity{ + Name: &zone, + }, + Profile: &vpcv1.VolumeProfileIdentity{ + Name: &profile, + }, + }, + } + 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{ + CRN: &encryptionKey, + } + } + + if rgrp, ok := d.GetOk(isVolumeResourceGroup); ok { + rg := rgrp.(string) + volTemplate.ResourceGroup = &vpcv1.ResourceGroupIdentity{ + ID: &rg, + } + } + + if i, ok := d.GetOk(isVolumeIops); ok { + iops := int64(i.(int)) + volTemplate.Iops = &iops + } + + var userTags *schema.Set + if v, ok := d.GetOk(isVolumeTags); ok { + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + schematicTags := os.Getenv("IC_ENV_TAGS") + var envTags []string + if schematicTags != "" { + envTags = strings.Split(schematicTags, ",") + userTagsArray = append(userTagsArray, envTags...) + } + volTemplate.UserTags = userTagsArray + } + } + + vol, response, err := sess.CreateVolume(options) + if err != nil { + return fmt.Errorf("[DEBUG] Create volume err %s\n%s", err, response) + } + d.SetId(*vol.ID) + log.Printf("[INFO] Volume : %s", *vol.ID) + _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + + if _, ok := d.GetOk(isVolumeAccessTags); ok { + oldList, newList := d.GetChange(isVolumeAccessTags) + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *vol.CRN, "", isVolumeAccessTagType) + if err != nil { + log.Printf( + "Error on create of resource vpc volume (%s) access tags: %s", d.Id(), err) + } + } + return nil +} + +func resourceIBMISInstanceBootVolumeRead(d *schema.ResourceData, meta interface{}) error { + + id := d.Id() + err := instancebootvolGet(d, meta, id) + if err != nil { + return err + } + return nil +} + +func instancebootvolGet(d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + options := &vpcv1.GetVolumeOptions{ + ID: &id, + } + vol, response, err := sess.GetVolume(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error getting Volume (%s): %s\n%s", id, err, response) + } + d.SetId(*vol.ID) + d.Set(isVolumeName, *vol.Name) + d.Set(isVolumeProfileName, *vol.Profile.Name) + d.Set(isVolumeZone, *vol.Zone.Name) + if vol.EncryptionKey != nil { + d.Set(isVolumeEncryptionKey, vol.EncryptionKey.CRN) + } + if vol.Encryption != nil { + d.Set(isVolumeEncryptionType, vol.Encryption) + } + d.Set(isVolumeIops, *vol.Iops) + d.Set(isVolumeCapacity, *vol.Capacity) + d.Set(isVolumeCrn, *vol.CRN) + if vol.SourceSnapshot != nil { + 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 { + statusReasonsList := make([]map[string]interface{}, 0) + for _, sr := range vol.StatusReasons { + currentSR := map[string]interface{}{} + if sr.Code != nil && sr.Message != nil { + currentSR[isVolumeStatusReasonsCode] = *sr.Code + currentSR[isVolumeStatusReasonsMessage] = *sr.Message + if sr.MoreInfo != nil { + currentSR[isVolumeStatusReasonsMoreInfo] = *sr.Message + } + statusReasonsList = append(statusReasonsList, currentSR) + } + } + d.Set(isVolumeStatusReasons, statusReasonsList) + } + if vol.UserTags != nil { + if err = d.Set(isVolumeTags, vol.UserTags); err != nil { + return fmt.Errorf("Error setting user tags: %s", err) + } + } + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *vol.CRN, "", isVolumeAccessTagType) + if err != nil { + log.Printf( + "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 + } + d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/storage/storageVolumes") + d.Set(flex.ResourceName, *vol.Name) + d.Set(flex.ResourceCRN, *vol.CRN) + d.Set(flex.ResourceStatus, *vol.Status) + if vol.ResourceGroup != nil { + d.Set(flex.ResourceGroupName, vol.ResourceGroup.Name) + d.Set(isVolumeResourceGroup, *vol.ResourceGroup.ID) + } + return nil +} + +func resourceIBMISInstanceBootVolumeUpdate(d *schema.ResourceData, meta interface{}) error { + + id := d.Id() + name := "" + hasNameChanged := false + delete := false + + if delete_all_snapshots, ok := d.GetOk(isVolumeDeleteAllSnapshots); ok && delete_all_snapshots.(bool) { + delete = true + } + + if d.HasChange(isVolumeName) { + name = d.Get(isVolumeName).(string) + hasNameChanged = true + } + + err := instancebootvolUpdate(d, meta, id, name, hasNameChanged, delete) + if err != nil { + return err + } + return resourceIBMISVolumeRead(d, meta) +} + +func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasNameChanged, delete bool) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + var capacity int64 + if delete { + deleteAllSnapshots(sess, id) + } + + if d.HasChange(isVolumeAccessTags) { + options := &vpcv1.GetVolumeOptions{ + ID: &id, + } + vol, response, err := sess.GetVolume(options) + if err != nil { + return fmt.Errorf("Error getting Volume : %s\n%s", err, response) + } + oldList, newList := d.GetChange(isVolumeAccessTags) + + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *vol.CRN, "", isVolumeAccessTagType) + if err != nil { + log.Printf( + "Error on update of resource vpc volume (%s) access tags: %s", id, err) + } + } + + optionsget := &vpcv1.GetVolumeOptions{ + ID: &id, + } + _, response, err := sess.GetVolume(optionsget) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("Error getting Volume (%s): %s\n%s", id, err, response) + } + eTag := response.Headers.Get("ETag") + options := &vpcv1.UpdateVolumeOptions{ + ID: &id, + } + options.IfMatch = &eTag + + //name update + volumeNamePatchModel := &vpcv1.VolumePatch{} + if hasNameChanged { + volumeNamePatchModel.Name = &name + volumeNamePatch, err := volumeNamePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for volumeNamePatch: %s", err) + } + options.VolumePatch = volumeNamePatch + _, _, err = sess.UpdateVolume(options) + _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + } + + // profile/ iops update + if d.HasChange(isVolumeProfileName) || d.HasChange(isVolumeIops) { + volumeProfilePatchModel := &vpcv1.VolumePatch{} + volId := d.Id() + getvoloptions := &vpcv1.GetVolumeOptions{ + ID: &volId, + } + vol, response, err := sess.GetVolume(getvoloptions) + if err != nil || vol == nil { + return fmt.Errorf("[ERROR] Error retrieving Volume (%s) details: %s\n%s", volId, err, response) + } + if vol.VolumeAttachments == nil || len(vol.VolumeAttachments) < 1 { + return fmt.Errorf("[ERROR] Error updating Volume profile/iops because the specified volume %s is not attached to a virtual server instance ", volId) + } + volAtt := &vol.VolumeAttachments[0] + insId := *volAtt.Instance.ID + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: &insId, + } + instance, response, err := sess.GetInstance(getinsOptions) + if err != nil || instance == nil { + return fmt.Errorf("[ERROR] Error retrieving Instance (%s) to which the volume (%s) is attached : %s\n%s", insId, volId, err, response) + } + if instance != nil && *instance.Status != "running" { + actiontype := "start" + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &insId, + Type: &actiontype, + } + _, response, err = sess.CreateInstanceAction(createinsactoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error starting Instance (%s) to which the volume (%s) is attached : %s\n%s", insId, volId, err, response) + } + _, err = isWaitForInstanceAvailable(sess, insId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return err + } + } + if d.HasChange(isVolumeProfileName) { + profile := d.Get(isVolumeProfileName).(string) + volumeProfilePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &profile, + } + } else if d.HasChange(isVolumeIops) { + profile := d.Get(isVolumeProfileName).(string) + volumeProfilePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ + Name: &profile, + } + iops := int64(d.Get(isVolumeIops).(int)) + volumeProfilePatchModel.Iops = &iops + } + + volumeProfilePatch, err := volumeProfilePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for VolumeProfilePatch: %s", err) + } + options.VolumePatch = volumeProfilePatch + _, response, err = sess.UpdateVolume(options) + _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + } + + // capacity update + if d.HasChange(isVolumeCapacity) { + id := d.Id() + getvolumeoptions := &vpcv1.GetVolumeOptions{ + ID: &id, + } + vol, response, err := sess.GetVolume(getvolumeoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("[ERROR] Error Getting Volume (%s): %s\n%s", id, err, response) + } + if vol.VolumeAttachments == nil || len(vol.VolumeAttachments) == 0 || *vol.VolumeAttachments[0].ID == "" { + return fmt.Errorf("[ERROR] Error volume capacity can't be updated since volume %s is not attached to any instance for VolumePatch", id) + } + insId := vol.VolumeAttachments[0].Instance.ID + getinsOptions := &vpcv1.GetInstanceOptions{ + ID: insId, + } + instance, response, err := sess.GetInstance(getinsOptions) + if err != nil || instance == nil { + return fmt.Errorf("[ERROR] Error retrieving Instance (%s) : %s\n%s", *insId, err, response) + } + if instance != nil && *instance.Status != "running" { + actiontype := "start" + createinsactoptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: insId, + Type: &actiontype, + } + _, response, err = sess.CreateInstanceAction(createinsactoptions) + if err != nil { + return fmt.Errorf("[ERROR] Error starting Instance (%s) : %s\n%s", *insId, err, response) + } + _, err = isWaitForInstanceAvailable(sess, *insId, d.Timeout(schema.TimeoutCreate), d) + if err != nil { + return err + } + } + capacity = int64(d.Get(isVolumeCapacity).(int)) + volumeCapacityPatchModel := &vpcv1.VolumePatch{} + volumeCapacityPatchModel.Capacity = &capacity + + volumeCapacityPatch, err := volumeCapacityPatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for volumeCapacityPatch: %s", err) + } + options.VolumePatch = volumeCapacityPatch + _, response, err = sess.UpdateVolume(options) + if err != nil { + return fmt.Errorf("[ERROR] Error updating vpc volume: %s\n%s", err, response) + } + _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + } + + // user tags update + if d.HasChange(isVolumeTags) { + var userTags *schema.Set + if v, ok := d.GetOk(isVolumeTags); ok { + userTags = v.(*schema.Set) + if userTags != nil && userTags.Len() != 0 { + userTagsArray := make([]string, userTags.Len()) + for i, userTag := range userTags.List() { + userTagStr := userTag.(string) + userTagsArray[i] = userTagStr + } + schematicTags := os.Getenv("IC_ENV_TAGS") + var envTags []string + if schematicTags != "" { + envTags = strings.Split(schematicTags, ",") + userTagsArray = append(userTagsArray, envTags...) + } + volumeNamePatchModel := &vpcv1.VolumePatch{} + volumeNamePatchModel.UserTags = userTagsArray + volumeNamePatch, err := volumeNamePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("Error calling asPatch for volumeNamePatch: %s", err) + } + options.IfMatch = &eTag + options.VolumePatch = volumeNamePatch + _, response, err := sess.UpdateVolume(options) + if err != nil { + return fmt.Errorf("Error updating volume : %s\n%s", err, response) + } + _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + if err != nil { + return err + } + } + } + } + + return nil +} + +func resourceIBMISInstanceBootVolumeDelete(d *schema.ResourceData, meta interface{}) error { + id := d.Id() + + err := instancebootvolDelete(d, meta, id) + if err != nil { + return err + } + return nil +} + +func instancebootvolDelete(d *schema.ResourceData, meta interface{}, id string) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } + + getvoloptions := &vpcv1.GetVolumeOptions{ + ID: &id, + } + volDetails, response, err := sess.GetVolume(getvoloptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil + } + return fmt.Errorf("[ERROR] Error getting Volume (%s): %s\n%s", id, err, response) + } + + if volDetails.VolumeAttachments != nil { + for _, volAtt := range volDetails.VolumeAttachments { + deleteVolumeAttachment := &vpcv1.DeleteInstanceVolumeAttachmentOptions{ + InstanceID: volAtt.Instance.ID, + ID: volAtt.ID, + } + _, err := sess.DeleteInstanceVolumeAttachment(deleteVolumeAttachment) + if err != nil { + return fmt.Errorf("[ERROR] Error while removing volume attachment %q for instance %s: %q", *volAtt.ID, *volAtt.Instance.ID, err) + } + _, err = isWaitForInstanceVolumeDetached(sess, d, d.Id(), *volAtt.ID) + if err != nil { + return err + } + + } + } + + options := &vpcv1.DeleteVolumeOptions{ + ID: &id, + } + response, err = sess.DeleteVolume(options) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting Volume : %s\n%s", err, response) + } + _, err = isWaitForVolumeDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } + d.SetId("") + return nil +} + +func isWaitForInstanceBootVolumeDeleted(vol *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for (%s) to be deleted.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", isVolumeDeleting}, + Target: []string{"done", ""}, + Refresh: isVolumeDeleteRefreshFunc(vol, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isInstanceBootVolumeDeleteRefreshFunc(vol *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + volgetoptions := &vpcv1.GetVolumeOptions{ + ID: &id, + } + vol, response, err := vol.GetVolume(volgetoptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return vol, isVolumeDeleted, nil + } + return vol, "", fmt.Errorf("[ERROR] Error getting Volume: %s\n%s", err, response) + } + return vol, isVolumeDeleting, err + } +} + +func resourceIBMISInstanceBootVolumeExists(d *schema.ResourceData, meta interface{}) (bool, error) { + + id := d.Id() + + exists, err := instancebootvolExists(d, meta, id) + return exists, err +} + +func instancebootvolExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { + sess, err := vpcClient(meta) + if err != nil { + return false, err + } + options := &vpcv1.GetVolumeOptions{ + ID: &id, + } + _, response, err := sess.GetVolume(options) + if err != nil { + if response != nil && response.StatusCode == 404 { + return false, nil + } + return false, fmt.Errorf("[ERROR] Error getting Volume: %s\n%s", err, response) + } + return true, nil +} + +func isWaitForInstanceBootVolumeAvailable(client *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { + log.Printf("Waiting for Volume (%s) to be available.", id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"retry", isVolumeProvisioning}, + Target: []string{isVolumeProvisioningDone, ""}, + Refresh: isVolumeRefreshFunc(client, id), + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + return stateConf.WaitForState() +} + +func isInstanceBootVolumeRefreshFunc(client *vpcv1.VpcV1, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + volgetoptions := &vpcv1.GetVolumeOptions{ + ID: &id, + } + vol, response, err := client.GetVolume(volgetoptions) + if err != nil { + return nil, "", fmt.Errorf("[ERROR] Error getting volume: %s\n%s", err, response) + } + + if *vol.Status == "available" { + return vol, isVolumeProvisioningDone, nil + } + + return vol, isVolumeProvisioning, nil + } +} + +func deleteAllInstanceBootSnapshots(sess *vpcv1.VpcV1, id string) error { + delete_all_snapshots := new(vpcv1.DeleteSnapshotsOptions) + delete_all_snapshots.SourceVolumeID = &id + response, err := sess.DeleteSnapshots(delete_all_snapshots) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting snapshots from volume %s\n%s", err, response) + } + return nil +} diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_test.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_test.go new file mode 100644 index 0000000000..d37f3b1e22 --- /dev/null +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_test.go @@ -0,0 +1,550 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package vpc_test + +import ( + "errors" + "fmt" + "strings" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccIBMISVolume_basic(t *testing.T) { + var vol string + name := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + name1 := fmt.Sprintf("tf-vol-upd-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVolumeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVolumeConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "name", name), + ), + }, + + { + Config: testAccCheckIBMISVolumeConfig(name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "name", name1), + ), + }, + }, + }) +} + +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)) + tagname := fmt.Sprintf("tfusertag%d", acctest.RandIntRange(10, 100)) + tagnameupdate := fmt.Sprintf("tfusertagupd%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVolumeDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIBMISVolumeUsertagConfig(name, tagname), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "name", name), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "tags.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "tags.0"), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "tags.0", tagname), + ), + }, + + resource.TestStep{ + Config: testAccCheckIBMISVolumeUsertagConfig(name, tagnameupdate), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "tags.#"), + resource.TestCheckResourceAttrSet( + "ibm_is_volume.storage", "tags.0"), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "tags.0", tagnameupdate), + ), + }, + }, + }) +} + +func TestAccIBMISVolumeUpdateCustom_basic(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)) + iops1 := int64(600) + iops2 := int64(900) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVolumeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVolumeCustomConfig(vpcname, subnetname, sshname, publicKey, name, volName, iops1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "name", volName), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "iops", fmt.Sprintf("%d", iops1)), + ), + }, + + { + Config: testAccCheckIBMISVolumeCustomConfig(vpcname, subnetname, sshname, publicKey, name, volName, iops2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "name", volName), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "iops", fmt.Sprintf("%d", iops2)), + ), + }, + }, + }) +} + +func TestAccIBMISVolumeUpdateTier_basic(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)) + profileName1 := "general-purpose" + profileName2 := "5iops-tier" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVolumeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVolumeTierConfig(vpcname, subnetname, sshname, publicKey, name, volName, profileName1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "name", volName), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "profile", profileName1), + ), + }, + + { + Config: testAccCheckIBMISVolumeTierConfig(vpcname, subnetname, sshname, publicKey, name, volName, profileName2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "name", volName), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "profile", profileName2), + ), + }, + }, + }) +} + +func TestAccIBMISVolumeUpdateCapacity_basic(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)) + capacity1 := int64(100) + capacity2 := int64(120) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVolumeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVolumeCapacityConfig(vpcname, subnetname, sshname, publicKey, name, volName, capacity1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "name", volName), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "capacity", fmt.Sprintf("%d", capacity1)), + ), + }, + + { + Config: testAccCheckIBMISVolumeCapacityConfig(vpcname, subnetname, sshname, publicKey, name, volName, capacity2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "name", volName), + resource.TestCheckResourceAttr( + "ibm_is_volume.storage", "capacity", fmt.Sprintf("%d", capacity2)), + ), + }, + }, + }) +} + +func TestAccIBMISVolumeAttachmentDelete_basic(t *testing.T) { + var vol string + insname := fmt.Sprintf("tf-ins-%d", acctest.RandIntRange(10, 100)) + initialVolumeCapacityArray := fmt.Sprintf("[%d, %d]", 10, 20) + finalVolumeCapacityArray := fmt.Sprintf("[%d]", 10) + vpcname := fmt.Sprintf("tf-vpc-%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)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVolumeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISVolumeAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, initialVolumeCapacityArray), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage.0", vol), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", insname), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "volume_attachments.#", "3"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "volumes.#", "2"), + ), + }, + + { + Config: testAccCheckIBMISVolumeAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, finalVolumeCapacityArray), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_volume.storage.0", vol), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "name", insname), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "volume_attachments.#", "2"), + resource.TestCheckResourceAttr( + "ibm_is_instance.testacc_instance", "volumes.#", "1"), + ), + }, + }, + }) +} + +func testAccCheckIBMISVolumeDestroy(s *terraform.State) error { + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_vol" { + continue + } + + getvolumeoptions := &vpcv1.GetVolumeOptions{ + ID: &rs.Primary.ID, + } + _, _, err := sess.GetVolume(getvolumeoptions) + + if err == nil { + return fmt.Errorf("[ERROR] Volume still exists: %s", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckIBMISVolumeExists(n, volID string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Record ID is set") + } + + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + getvolumeoptions := &vpcv1.GetVolumeOptions{ + ID: &rs.Primary.ID, + } + foundvol, _, err := sess.GetVolume(getvolumeoptions) + if err != nil { + return err + } + volID = *foundvol.ID + return nil + } +} + +func testAccCheckIBMISVolumeConfig(name string) string { + return fmt.Sprintf( + ` + resource "ibm_is_volume" "storage"{ + name = "%s" + profile = "10iops-tier" + zone = "us-south-1" + # capacity= 200 + } +`, name) + +} + +func testAccCheckIBMISVolumeCustomConfig(vpcname, subnetname, sshname, publicKey, name, volName string, iops int64) string { + return fmt.Sprintf( + ` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + resource "ibm_is_volume" "storage"{ + name = "%s" + profile = "custom" + zone = "%s" + iops = %d + } + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + volumes = [ibm_is_volume.storage.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, volName, acc.ISZoneName, iops, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) + +} + +func testAccCheckIBMISVolumeTierConfig(vpcname, subnetname, sshname, publicKey, name, volName, profileName string) string { + return fmt.Sprintf( + ` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + resource "ibm_is_volume" "storage"{ + name = "%s" + profile = "%s" + zone = "%s" + } + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + volumes = [ibm_is_volume.storage.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, volName, profileName, acc.ISZoneName, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) + +} + +func testAccCheckIBMISVolumeAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, capacityArray string) string { + return fmt.Sprintf( + ` + variable "vsi_vol_size" { + description = "capacity array" + default = %s + } + + resource "ibm_is_volume" "storage"{ + name = "tf-vol-att-${count.index}" + count = length(var.vsi_vol_size) + profile = "general-purpose" + zone = "%s" + capacity = var.vsi_vol_size[count.index] + } + + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + volumes = ibm_is_volume.storage[*].id + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } +`, capacityArray, acc.ISZoneName, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, insname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) + +} + +func testAccCheckIBMISVolumeCapacityConfig(vpcname, subnetname, sshname, publicKey, name, volName string, capacity int64) string { + return fmt.Sprintf( + ` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + resource "ibm_is_volume" "storage"{ + name = "%s" + profile = "10iops-tier" + zone = "%s" + capacity = %d + } + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + image = "%s" + profile = "%s" + volumes = [ibm_is_volume.storage.id] + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + +`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, volName, acc.ISZoneName, capacity, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) + +} + +func testAccCheckIBMISVolumeUsertagConfig(name, usertag string) string { + return fmt.Sprintf( + ` + resource "ibm_is_volume" "storage"{ + name = "%s" + profile = "10iops-tier" + zone = "us-south-1" + # capacity= 200 + tags = ["%s"] + } +`, 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) +} From 7f74fafc43241e7cf96ad0e032a8b423061f268f Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Thu, 23 Mar 2023 19:11:41 +0530 Subject: [PATCH 02/21] added docs and provider details --- examples/ibm-is-ng/main.tf | 9 ++ ibm/provider/provider.go | 1 + .../r/is_instance_boot_volume.html.markdown | 121 ++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 website/docs/r/is_instance_boot_volume.html.markdown diff --git a/examples/ibm-is-ng/main.tf b/examples/ibm-is-ng/main.tf index 52f31f7f53..4394dd85cd 100644 --- a/examples/ibm-is-ng/main.tf +++ b/examples/ibm-is-ng/main.tf @@ -1195,4 +1195,13 @@ data "ibm_is_vpn_server_clients" "is_vpn_server_clients" { data "ibm_is_vpn_server_client" "is_vpn_server_client" { vpn_server_id = ibm_is_vpn_server.is_vpn_server.vpn_server identifier = "0726-61b2f53f-1e95-42a7-94ab-55de8f8cbdd5" +} + +// vsi boot volume + +resource "ibm_is_instance_boot_volume" "vol1" { + volume = ibm_is_instance.boot_volume.0.volume_id + name = "vol1" + profile = "10iops-tier" + zone = var.zone1 } \ No newline at end of file diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 3915d1a78a..5506a12307 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -948,6 +948,7 @@ func Provider() *schema.Provider { "ibm_is_flow_log": vpc.ResourceIBMISFlowLog(), "ibm_is_instance": vpc.ResourceIBMISInstance(), "ibm_is_instance_action": vpc.ResourceIBMISInstanceAction(), + "ibm_is_instance_boot_volume": vpc.ResourceIBMISInstanceBootVolume(), "ibm_is_instance_network_interface": vpc.ResourceIBMIsInstanceNetworkInterface(), "ibm_is_instance_network_interface_floating_ip": vpc.ResourceIBMIsInstanceNetworkInterfaceFloatingIp(), "ibm_is_instance_disk_management": vpc.ResourceIBMISInstanceDiskManagement(), diff --git a/website/docs/r/is_instance_boot_volume.html.markdown b/website/docs/r/is_instance_boot_volume.html.markdown new file mode 100644 index 0000000000..5342abe18e --- /dev/null +++ b/website/docs/r/is_instance_boot_volume.html.markdown @@ -0,0 +1,121 @@ +--- + +subcategory: "VPC infrastructure" +layout: "ibm" +page_title: "IBM : instance_boot_volume" +description: |- + Manages IBM volume. +--- + +# ibm_is_instance_boot_volume +Provides a resource to manage a boot volume of a VPC virtual server instance. Manage the boot volume of a VPC virtual server instance created alongwith the instance creation with this resource. + +~> **NOTE:** This is an advanced resource with special caveats. Please read this document in its entirety before using this resource. The `ibm_is_instance_boot_volume` resource behaves differently from normal resources. Terraform does not _create_ this resource but instead attempts to "adopt" it into management. + +Every Virtual server instance has a boot volume that can be managed but not destroyed. When Terraform first adopts a instance_boot_volume, + +For more information, about VPC, see [getting started with Virtual Private Cloud](https://cloud.ibm.com/docs/vpc?topic=vpc-getting-started). For more information, about updating default security group, see [updating a VPC's default security group rules](https://cloud.ibm.com/docs/vpc?topic=vpc-updating-the-default-security-group&interface=ui). + +~> **NOTE:** +VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. + +**provider.tf** + +```terraform +provider "ibm" { + region = "eu-gb" +} +``` + +## Example usage +The following example creates a volume with 10 IOPs tier. + +```terraform +resource "ibm_is_instance_boot_volume" "example" { + name = "example-volume" + profile = "10iops-tier" + zone = "us-south-1" +} +``` + +## Timeouts +The `ibm_is_instance_boot_volume` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 10 minutes) Used for creating instance. +- **delete** - (Default 10 minutes) Used for deleting instance. + + +## Argument reference +Review the argument references that you can specify for your resource. + +- `access_tags` - (Optional, List of Strings) A list of access management tags to attach to the bare metal server. + + ~> **Note:** + **•** You can attach only those access tags that already exists.
+ **•** For more information, about creating access tags, see [working with tags](https://cloud.ibm.com/docs/account?topic=account-tag&interface=ui#create-access-console).
+ **•** You must have the access listed in the [Granting users access to tag resources](https://cloud.ibm.com/docs/account?topic=account-access) for `access_tags`
+ **•** `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.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. +- `encryption_key` - (Optional, Forces new resource, String) The key to use for encrypting this volume. +- `iops` - (Optional, Integer) The total input/ output operations per second (IOPS) for your storage. This value is required for `custom` storage profiles only. + + ~> **NOTE:** `iops` value can be upgraded and downgraged if volume is attached to an running virtual server instance. Stopped instances will be started on update of volume. + + This table shows how storage size affects the `iops` ranges: + + | Size range (GB) | IOPS range | + |--------------------|----------------| + | 10 - 39 | 100 - 1000 | + | 40 - 79 | 100 - 2000 | + | 80 - 99 | 100 - 4000 | + | 100 - 499 | 100 - 6000 | + | 500 - 999 | 100 - 10000 | + | 1000 - 1999 | 100 - 20000 | + | 2000 - 3999 | 100 - 40000 | + | 4000 - 1999 | 100 - 40000 | + | 8000 - 1999 | 100 - 48000 | + | 10000 - 16000 | 100 - 48000 | + +- `name` - (Required, String) The user-defined name for this volume.No. +- `profile` - (Required, String) The profile to use for this volume. + + ~> **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. +- `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. + + Nested scheme for `status_reasons`: + - `code` - (String) A string with an underscore as a special character identifying the status reason. + - `message` - (String) An explanation of the status reason. + - `more_info` - (String) Link to documentation about this status reason +- `crn` - (String) The CRN for the volume. + +## Import +The `ibm_is_instance_boot_volume` resource can be imported by using volume ID. + +**Example** + +``` +$ terraform import ibm_is_instance_boot_volume.example d7bec597-4726-451f-8a63-e62e6f19c32c +``` From fa64e4f2e3893d68a2699f85f92f6c1f6a57b703 Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Fri, 24 Mar 2023 12:18:23 +0530 Subject: [PATCH 03/21] Update resource_ibm_is_instance_boot_volume_test.go --- ...source_ibm_is_instance_boot_volume_test.go | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_test.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_test.go index d37f3b1e22..34a77505e7 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_test.go @@ -18,7 +18,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -func TestAccIBMISVolume_basic(t *testing.T) { +func TestAccIBMISInstanceBootVolume_basic(t *testing.T) { var vol string name := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) name1 := fmt.Sprintf("tf-vol-upd-%d", acctest.RandIntRange(10, 100)) @@ -49,7 +49,7 @@ func TestAccIBMISVolume_basic(t *testing.T) { }) } -func TestAccIBMISVolume_snapshot(t *testing.T) { +func TestAccIBMISInstanceBootVolume_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)) @@ -78,7 +78,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } -func TestAccIBMISVolumeUsertag_basic(t *testing.T) { +func TestAccIBMISInstanceBootVolumeUsertag_basic(t *testing.T) { var vol string name := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) tagname := fmt.Sprintf("tfusertag%d", acctest.RandIntRange(10, 100)) @@ -120,7 +120,7 @@ func TestAccIBMISVolumeUsertag_basic(t *testing.T) { }) } -func TestAccIBMISVolumeUpdateCustom_basic(t *testing.T) { +func TestAccIBMISInstanceBootVolumeUpdateCustom_basic(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)) @@ -163,7 +163,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }) } -func TestAccIBMISVolumeUpdateTier_basic(t *testing.T) { +func TestAccIBMISInstanceBootVolumeUpdateTier_basic(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)) @@ -206,7 +206,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }) } -func TestAccIBMISVolumeUpdateCapacity_basic(t *testing.T) { +func TestAccIBMISInstanceBootVolumeUpdateCapacity_basic(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)) @@ -249,7 +249,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }) } -func TestAccIBMISVolumeAttachmentDelete_basic(t *testing.T) { +func TestAccIBMISInstanceBootVolumeAttachmentDelete_basic(t *testing.T) { var vol string insname := fmt.Sprintf("tf-ins-%d", acctest.RandIntRange(10, 100)) initialVolumeCapacityArray := fmt.Sprintf("[%d, %d]", 10, 20) @@ -294,7 +294,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }) } -func testAccCheckIBMISVolumeDestroy(s *terraform.State) error { +func testAccCheckIBMISInstanceBootVolumeDestroy(s *terraform.State) error { sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { @@ -315,7 +315,7 @@ func testAccCheckIBMISVolumeDestroy(s *terraform.State) error { return nil } -func testAccCheckIBMISVolumeExists(n, volID string) resource.TestCheckFunc { +func testAccCheckIBMISInstanceBootVolumeExists(n, volID string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -340,7 +340,7 @@ func testAccCheckIBMISVolumeExists(n, volID string) resource.TestCheckFunc { } } -func testAccCheckIBMISVolumeConfig(name string) string { +func testAccCheckIBMISInstanceBootVolumeConfig(name string) string { return fmt.Sprintf( ` resource "ibm_is_volume" "storage"{ @@ -353,7 +353,7 @@ func testAccCheckIBMISVolumeConfig(name string) string { } -func testAccCheckIBMISVolumeCustomConfig(vpcname, subnetname, sshname, publicKey, name, volName string, iops int64) string { +func testAccCheckIBMISInstanceBootVolumeCustomConfig(vpcname, subnetname, sshname, publicKey, name, volName string, iops int64) string { return fmt.Sprintf( ` resource "ibm_is_vpc" "testacc_vpc" { @@ -394,7 +394,7 @@ func testAccCheckIBMISVolumeCustomConfig(vpcname, subnetname, sshname, publicKey } -func testAccCheckIBMISVolumeTierConfig(vpcname, subnetname, sshname, publicKey, name, volName, profileName string) string { +func testAccCheckIBMISInstanceBootVolumeTierConfig(vpcname, subnetname, sshname, publicKey, name, volName, profileName string) string { return fmt.Sprintf( ` resource "ibm_is_vpc" "testacc_vpc" { @@ -434,7 +434,7 @@ func testAccCheckIBMISVolumeTierConfig(vpcname, subnetname, sshname, publicKey, } -func testAccCheckIBMISVolumeAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, capacityArray string) string { +func testAccCheckIBMISInstanceBootVolumeAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, capacityArray string) string { return fmt.Sprintf( ` variable "vsi_vol_size" { @@ -482,7 +482,7 @@ func testAccCheckIBMISVolumeAttachmentDeleteConfig(vpcname, subnetname, sshname, } -func testAccCheckIBMISVolumeCapacityConfig(vpcname, subnetname, sshname, publicKey, name, volName string, capacity int64) string { +func testAccCheckIBMISInstanceBootVolumeCapacityConfig(vpcname, subnetname, sshname, publicKey, name, volName string, capacity int64) string { return fmt.Sprintf( ` resource "ibm_is_vpc" "testacc_vpc" { @@ -523,7 +523,7 @@ func testAccCheckIBMISVolumeCapacityConfig(vpcname, subnetname, sshname, publicK } -func testAccCheckIBMISVolumeUsertagConfig(name, usertag string) string { +func testAccCheckIBMISInstanceBootVolumeUsertagConfig(name, usertag string) string { return fmt.Sprintf( ` resource "ibm_is_volume" "storage"{ @@ -537,7 +537,7 @@ func testAccCheckIBMISVolumeUsertagConfig(name, usertag string) string { } -func testAccCheckIBMISVolumeConfigSnapshot(vpcname, subnetname, sshname, publicKey, volname, name, name1 string) string { +func testAccCheckIBMISInstanceBootVolumeConfigSnapshot(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" { From 8b633dbb508ae50b894725f6c17e82e6f8d2b8ad Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Fri, 24 Mar 2023 15:47:58 +0530 Subject: [PATCH 04/21] fix --- ibm/provider/provider.go | 1 + .../resource_ibm_is_instance_boot_volume.go | 252 +++++------------- 2 files changed, 69 insertions(+), 184 deletions(-) diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index eee95ad17f..820ea2ac21 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -1337,6 +1337,7 @@ func Validator() validate.ValidatorDict { "ibm_is_instance_template": vpc.ResourceIBMISInstanceTemplateValidator(), "ibm_is_instance": vpc.ResourceIBMISInstanceValidator(), "ibm_is_instance_action": vpc.ResourceIBMISInstanceActionValidator(), + "ibm_is_instance_boot_volume": vpc.ResourceIBMISInstanceBootVolumeValidator(), "ibm_is_instance_network_interface": vpc.ResourceIBMIsInstanceNetworkInterfaceValidator(), "ibm_is_instance_disk_management": vpc.ResourceIBMISInstanceDiskManagementValidator(), "ibm_is_instance_volume_attachment": vpc.ResourceIBMISInstanceVolumeAttachmentValidator(), diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go index 204df56984..0b1d89460f 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go @@ -19,8 +19,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -const () - func ResourceIBMISInstanceBootVolume() *schema.Resource { return &schema.Resource{ Create: resourceIBMISInstanceBootVolumeCreate, @@ -53,31 +51,38 @@ func ResourceIBMISInstanceBootVolume() *schema.Resource { Schema: map[string]*schema.Schema{ - isVolumeName: { + isInstanceBootVolumeId: { Type: schema.TypeString, Required: true, - ValidateFunc: validate.InvokeValidator("ibm_is_volume", isVolumeName), + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume", isVolumeName), + Description: "Volume name", + }, + isVolumeName: { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume", isVolumeName), Description: "Volume name", }, isVolumeProfileName: { Type: schema.TypeString, - Required: true, - ValidateFunc: validate.InvokeValidator("ibm_is_volume", isVolumeProfileName), + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume", isVolumeProfileName), Description: "Volume profile name", }, isVolumeZone: { Type: schema.TypeString, - Required: true, - ForceNew: true, + Computed: true, Description: "Zone name", }, isVolumeEncryptionKey: { Type: schema.TypeString, - Optional: true, - ForceNew: true, + Computed: true, Description: "Volume encryption key info", }, @@ -90,31 +95,25 @@ func ResourceIBMISInstanceBootVolume() *schema.Resource { isVolumeCapacity: { Type: schema.TypeInt, Optional: true, - ForceNew: false, Computed: true, - ValidateFunc: validate.InvokeValidator("ibm_is_volume", isVolumeCapacity), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_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", + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this snapshot", }, isVolumeResourceGroup: { Type: schema.TypeString, - Optional: true, Computed: true, - ForceNew: true, Description: "Resource group name", }, isVolumeIops: { Type: schema.TypeInt, Optional: true, Computed: true, - ValidateFunc: validate.InvokeValidator("ibm_is_volume", isVolumeIops), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume", isVolumeIops), Description: "IOPS value for the Volume", }, isVolumeCrn: { @@ -193,7 +192,7 @@ func ResourceIBMISInstanceBootVolume() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_volume", "tags")}, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume", "tags")}, Set: flex.ResourceIBMVPCHash, Description: "UserTags for the volume instance", }, @@ -201,7 +200,7 @@ func ResourceIBMISInstanceBootVolume() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_volume", "accesstag")}, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume", "accesstag")}, Set: flex.ResourceIBMVPCHash, Description: "Access management tags for the volume instance", }, @@ -257,7 +256,11 @@ func ResourceIBMISInstanceBootVolumeValidator() *validate.ResourceValidator { Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) - + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: isInstanceBootVolumeId, + ValidateFunctionIdentifier: validate.ValidateNoZeroValues, + Type: validate.TypeString}) validateSchema = append(validateSchema, validate.ValidateSchema{ Identifier: "tags", @@ -308,139 +311,20 @@ func ResourceIBMISInstanceBootVolumeValidator() *validate.ResourceValidator { MinValueLength: 1, MaxValueLength: 128}) - ibmISVolumeResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_volume", Schema: validateSchema} + ibmISVolumeResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_boot_volume", Schema: validateSchema} return &ibmISVolumeResourceValidator } func resourceIBMISInstanceBootVolumeCreate(d *schema.ResourceData, meta interface{}) error { - volName := d.Get(isVolumeName).(string) - profile := d.Get(isVolumeProfileName).(string) - zone := d.Get(isVolumeZone).(string) - - err := instanceBootVolCreate(d, meta, volName, profile, zone) + volId := d.Get(isInstanceBootVolumeId).(string) + d.SetId(volId) + err := resourceIBMISInstanceBootVolumeRead(d, meta) if err != nil { return err } - return resourceIBMISVolumeRead(d, meta) -} - -func instanceBootVolCreate(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, - Zone: &vpcv1.ZoneIdentity{ - Name: &zone, - }, - Profile: &vpcv1.VolumeProfileIdentity{ - Name: &profile, - }, - }, - } - 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{ - CRN: &encryptionKey, - } - } - - if rgrp, ok := d.GetOk(isVolumeResourceGroup); ok { - rg := rgrp.(string) - volTemplate.ResourceGroup = &vpcv1.ResourceGroupIdentity{ - ID: &rg, - } - } - - if i, ok := d.GetOk(isVolumeIops); ok { - iops := int64(i.(int)) - volTemplate.Iops = &iops - } - - var userTags *schema.Set - if v, ok := d.GetOk(isVolumeTags); ok { - userTags = v.(*schema.Set) - if userTags != nil && userTags.Len() != 0 { - userTagsArray := make([]string, userTags.Len()) - for i, userTag := range userTags.List() { - userTagStr := userTag.(string) - userTagsArray[i] = userTagStr - } - schematicTags := os.Getenv("IC_ENV_TAGS") - var envTags []string - if schematicTags != "" { - envTags = strings.Split(schematicTags, ",") - userTagsArray = append(userTagsArray, envTags...) - } - volTemplate.UserTags = userTagsArray - } - } - - vol, response, err := sess.CreateVolume(options) - if err != nil { - return fmt.Errorf("[DEBUG] Create volume err %s\n%s", err, response) - } - d.SetId(*vol.ID) - log.Printf("[INFO] Volume : %s", *vol.ID) - _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) - if err != nil { - return err - } - - if _, ok := d.GetOk(isVolumeAccessTags); ok { - oldList, newList := d.GetChange(isVolumeAccessTags) - err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *vol.CRN, "", isVolumeAccessTagType) - if err != nil { - log.Printf( - "Error on create of resource vpc volume (%s) access tags: %s", d.Id(), err) - } - } - return nil + return resourceIBMISInstanceBootVolumeUpdate(d, meta) } func resourceIBMISInstanceBootVolumeRead(d *schema.ResourceData, meta interface{}) error { @@ -467,7 +351,7 @@ func instancebootvolGet(d *schema.ResourceData, meta interface{}, id string) err d.SetId("") return nil } - return fmt.Errorf("[ERROR] Error getting Volume (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error getting Instance boot volume (%s): %s\n%s", id, err, response) } d.SetId(*vol.ID) d.Set(isVolumeName, *vol.Name) @@ -567,7 +451,7 @@ func resourceIBMISInstanceBootVolumeUpdate(d *schema.ResourceData, meta interfac if err != nil { return err } - return resourceIBMISVolumeRead(d, meta) + return resourceIBMISInstanceBootVolumeRead(d, meta) } func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasNameChanged, delete bool) error { @@ -577,7 +461,7 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name st } var capacity int64 if delete { - deleteAllSnapshots(sess, id) + deleteAllInstanceBootSnapshots(sess, id) } if d.HasChange(isVolumeAccessTags) { @@ -586,14 +470,14 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name st } vol, response, err := sess.GetVolume(options) if err != nil { - return fmt.Errorf("Error getting Volume : %s\n%s", err, response) + return fmt.Errorf("Error getting Instance boot volume : %s\n%s", err, response) } oldList, newList := d.GetChange(isVolumeAccessTags) err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *vol.CRN, "", isVolumeAccessTagType) if err != nil { log.Printf( - "Error on update of resource vpc volume (%s) access tags: %s", id, err) + "Error on update of resource Instance boot volume (%s) access tags: %s", id, err) } } @@ -606,7 +490,7 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name st d.SetId("") return nil } - return fmt.Errorf("Error getting Volume (%s): %s\n%s", id, err, response) + return fmt.Errorf("Error getting Instance boot volume (%s): %s\n%s", id, err, response) } eTag := response.Headers.Get("ETag") options := &vpcv1.UpdateVolumeOptions{ @@ -620,11 +504,11 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name st volumeNamePatchModel.Name = &name volumeNamePatch, err := volumeNamePatchModel.AsPatch() if err != nil { - return fmt.Errorf("[ERROR] Error calling asPatch for volumeNamePatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for volumeNamePatch in Instance boot volume : %s", err) } options.VolumePatch = volumeNamePatch _, _, err = sess.UpdateVolume(options) - _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + _, err = isWaitForInstanceBootVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) if err != nil { return err } @@ -639,10 +523,10 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name st } vol, response, err := sess.GetVolume(getvoloptions) if err != nil || vol == nil { - return fmt.Errorf("[ERROR] Error retrieving Volume (%s) details: %s\n%s", volId, err, response) + return fmt.Errorf("[ERROR] Error retrieving Instance boot volume (%s) details: %s\n%s", volId, err, response) } if vol.VolumeAttachments == nil || len(vol.VolumeAttachments) < 1 { - return fmt.Errorf("[ERROR] Error updating Volume profile/iops because the specified volume %s is not attached to a virtual server instance ", volId) + return fmt.Errorf("[ERROR] Error updating Instance boot volume profile/iops because the specified volume %s is not attached to a virtual server instance ", volId) } volAtt := &vol.VolumeAttachments[0] insId := *volAtt.Instance.ID @@ -651,7 +535,7 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name st } instance, response, err := sess.GetInstance(getinsOptions) if err != nil || instance == nil { - return fmt.Errorf("[ERROR] Error retrieving Instance (%s) to which the volume (%s) is attached : %s\n%s", insId, volId, err, response) + return fmt.Errorf("[ERROR] Error retrieving Instance (%s) to which the boot volume (%s) is attached : %s\n%s", insId, volId, err, response) } if instance != nil && *instance.Status != "running" { actiontype := "start" @@ -661,7 +545,7 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name st } _, response, err = sess.CreateInstanceAction(createinsactoptions) if err != nil { - return fmt.Errorf("[ERROR] Error starting Instance (%s) to which the volume (%s) is attached : %s\n%s", insId, volId, err, response) + return fmt.Errorf("[ERROR] Error starting Instance (%s) to which the boot volume (%s) is attached : %s\n%s", insId, volId, err, response) } _, err = isWaitForInstanceAvailable(sess, insId, d.Timeout(schema.TimeoutCreate), d) if err != nil { @@ -684,11 +568,11 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name st volumeProfilePatch, err := volumeProfilePatchModel.AsPatch() if err != nil { - return fmt.Errorf("[ERROR] Error calling asPatch for VolumeProfilePatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for VolumeProfilePatch in Instance boot volume : %s", err) } options.VolumePatch = volumeProfilePatch _, response, err = sess.UpdateVolume(options) - _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + _, err = isWaitForInstanceBootVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) if err != nil { return err } @@ -706,10 +590,10 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name st d.SetId("") return nil } - return fmt.Errorf("[ERROR] Error Getting Volume (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error Getting Instance boot volume (%s): %s\n%s", id, err, response) } if vol.VolumeAttachments == nil || len(vol.VolumeAttachments) == 0 || *vol.VolumeAttachments[0].ID == "" { - return fmt.Errorf("[ERROR] Error volume capacity can't be updated since volume %s is not attached to any instance for VolumePatch", id) + return fmt.Errorf("[ERROR] Error volume capacity can't be updated since Instance boot volume %s is not attached to any instance for VolumePatch", id) } insId := vol.VolumeAttachments[0].Instance.ID getinsOptions := &vpcv1.GetInstanceOptions{ @@ -740,14 +624,14 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name st volumeCapacityPatch, err := volumeCapacityPatchModel.AsPatch() if err != nil { - return fmt.Errorf("[ERROR] Error calling asPatch for volumeCapacityPatch: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for volumeCapacityPatch in Instance boot volume : %s", err) } options.VolumePatch = volumeCapacityPatch _, response, err = sess.UpdateVolume(options) if err != nil { - return fmt.Errorf("[ERROR] Error updating vpc volume: %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error updating Instance boot volume: %s\n%s", err, response) } - _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + _, err = isWaitForInstanceBootVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) if err != nil { return err } @@ -774,15 +658,15 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name st volumeNamePatchModel.UserTags = userTagsArray volumeNamePatch, err := volumeNamePatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for volumeNamePatch: %s", err) + return fmt.Errorf("Error calling asPatch for volumeNamePatch in Instance boot volume: %s", err) } options.IfMatch = &eTag options.VolumePatch = volumeNamePatch _, response, err := sess.UpdateVolume(options) if err != nil { - return fmt.Errorf("Error updating volume : %s\n%s", err, response) + return fmt.Errorf("Error updating Instance boot volume : %s\n%s", err, response) } - _, err = isWaitForVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + _, err = isWaitForInstanceBootVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) if err != nil { return err } @@ -794,12 +678,12 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name st } func resourceIBMISInstanceBootVolumeDelete(d *schema.ResourceData, meta interface{}) error { - id := d.Id() - - err := instancebootvolDelete(d, meta, id) - if err != nil { - return err - } + // id := d.Id() + d.SetId("") + // err := instancebootvolDelete(d, meta, id) + // if err != nil { + // return err + // } return nil } @@ -817,7 +701,7 @@ func instancebootvolDelete(d *schema.ResourceData, meta interface{}, id string) if response != nil && response.StatusCode == 404 { return nil } - return fmt.Errorf("[ERROR] Error getting Volume (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error getting Instance boot volume (%s): %s\n%s", id, err, response) } if volDetails.VolumeAttachments != nil { @@ -843,9 +727,9 @@ func instancebootvolDelete(d *schema.ResourceData, meta interface{}, id string) } response, err = sess.DeleteVolume(options) if err != nil { - return fmt.Errorf("[ERROR] Error deleting Volume : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error deleting Instance boot volume : %s\n%s", err, response) } - _, err = isWaitForVolumeDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) + _, err = isWaitForInstanceBootVolumeDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) if err != nil { return err } @@ -878,7 +762,7 @@ func isInstanceBootVolumeDeleteRefreshFunc(vol *vpcv1.VpcV1, id string) resource if response != nil && response.StatusCode == 404 { return vol, isVolumeDeleted, nil } - return vol, "", fmt.Errorf("[ERROR] Error getting Volume: %s\n%s", err, response) + return vol, "", fmt.Errorf("[ERROR] Error getting Instance boot volume: %s\n%s", err, response) } return vol, isVolumeDeleting, err } @@ -905,13 +789,13 @@ func instancebootvolExists(d *schema.ResourceData, meta interface{}, id string) if response != nil && response.StatusCode == 404 { return false, nil } - return false, fmt.Errorf("[ERROR] Error getting Volume: %s\n%s", err, response) + return false, fmt.Errorf("[ERROR] Error getting Instance boot volume: %s\n%s", err, response) } return true, nil } func isWaitForInstanceBootVolumeAvailable(client *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for Volume (%s) to be available.", id) + log.Printf("Waiting for Instance boot volume (%s) to be available.", id) stateConf := &resource.StateChangeConf{ Pending: []string{"retry", isVolumeProvisioning}, @@ -932,7 +816,7 @@ func isInstanceBootVolumeRefreshFunc(client *vpcv1.VpcV1, id string) resource.St } vol, response, err := client.GetVolume(volgetoptions) if err != nil { - return nil, "", fmt.Errorf("[ERROR] Error getting volume: %s\n%s", err, response) + return nil, "", fmt.Errorf("[ERROR] Error getting Instance boot volume: %s\n%s", err, response) } if *vol.Status == "available" { @@ -948,7 +832,7 @@ func deleteAllInstanceBootSnapshots(sess *vpcv1.VpcV1, id string) error { delete_all_snapshots.SourceVolumeID = &id response, err := sess.DeleteSnapshots(delete_all_snapshots) if err != nil { - return fmt.Errorf("[ERROR] Error deleting snapshots from volume %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error deleting snapshots from Instance boot volume %s\n%s", err, response) } return nil } From fd955d838307dff5a5c834793c2decbc73cb7a6d Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Fri, 21 Apr 2023 12:41:42 +0530 Subject: [PATCH 05/21] Update resource_ibm_is_instance_boot_volume.go --- .../resource_ibm_is_instance_boot_volume.go | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go index 0b1d89460f..5d90f0c199 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go @@ -432,6 +432,18 @@ func instancebootvolGet(d *schema.ResourceData, meta interface{}, id string) err } func resourceIBMISInstanceBootVolumeUpdate(d *schema.ResourceData, meta interface{}) error { + err := instancebootvolUpdate(d, meta) + if err != nil { + return err + } + return resourceIBMISInstanceBootVolumeRead(d, meta) +} + +func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { + sess, err := vpcClient(meta) + if err != nil { + return err + } id := d.Id() name := "" @@ -446,19 +458,6 @@ func resourceIBMISInstanceBootVolumeUpdate(d *schema.ResourceData, meta interfac name = d.Get(isVolumeName).(string) hasNameChanged = true } - - err := instancebootvolUpdate(d, meta, id, name, hasNameChanged, delete) - if err != nil { - return err - } - return resourceIBMISInstanceBootVolumeRead(d, meta) -} - -func instancebootvolUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasNameChanged, delete bool) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } var capacity int64 if delete { deleteAllInstanceBootSnapshots(sess, id) From 83aedff61a9d17121a8d4142b2e57aa627ad830d Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Fri, 21 Apr 2023 13:24:07 +0530 Subject: [PATCH 06/21] Update resource_ibm_is_instance_boot_volume.go --- .../resource_ibm_is_instance_boot_volume.go | 79 +++++++------------ 1 file changed, 27 insertions(+), 52 deletions(-) diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go index 5d90f0c199..fca51a73bb 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go @@ -19,6 +19,10 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) +const ( + isInstanceBootVolumeDelete = "delete" +) + func ResourceIBMISInstanceBootVolume() *schema.Resource { return &schema.Resource{ Create: resourceIBMISInstanceBootVolumeCreate, @@ -86,6 +90,12 @@ func ResourceIBMISInstanceBootVolume() *schema.Resource { Description: "Volume encryption key info", }, + isInstanceBootVolumeDelete: { + Type: schema.TypeBool, + Optional: true, + Description: "Volume encryption key info", + }, + isVolumeEncryptionType: { Type: schema.TypeString, Computed: true, @@ -677,60 +687,25 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceIBMISInstanceBootVolumeDelete(d *schema.ResourceData, meta interface{}) error { - // id := d.Id() - d.SetId("") - // err := instancebootvolDelete(d, meta, id) - // if err != nil { - // return err - // } - return nil -} - -func instancebootvolDelete(d *schema.ResourceData, meta interface{}, id string) error { - sess, err := vpcClient(meta) - if err != nil { - return err - } - - getvoloptions := &vpcv1.GetVolumeOptions{ - ID: &id, - } - volDetails, response, err := sess.GetVolume(getvoloptions) - if err != nil { - if response != nil && response.StatusCode == 404 { - return nil + id := d.Id() + // check if force delete is true + if d.Get(isInstanceBootVolumeDelete).(bool) { + sess, err := vpcClient(meta) + if err != nil { + return err } - return fmt.Errorf("[ERROR] Error getting Instance boot volume (%s): %s\n%s", id, err, response) - } - - if volDetails.VolumeAttachments != nil { - for _, volAtt := range volDetails.VolumeAttachments { - deleteVolumeAttachment := &vpcv1.DeleteInstanceVolumeAttachmentOptions{ - InstanceID: volAtt.Instance.ID, - ID: volAtt.ID, - } - _, err := sess.DeleteInstanceVolumeAttachment(deleteVolumeAttachment) - if err != nil { - return fmt.Errorf("[ERROR] Error while removing volume attachment %q for instance %s: %q", *volAtt.ID, *volAtt.Instance.ID, err) - } - _, err = isWaitForInstanceVolumeDetached(sess, d, d.Id(), *volAtt.ID) - if err != nil { - return err - } + options := &vpcv1.DeleteVolumeOptions{ + ID: &id, + } + response, err := sess.DeleteVolume(options) + if err != nil { + return fmt.Errorf("[ERROR] Error deleting Volume : %s\n%s", err, response) + } + _, err = isWaitForInstanceBootVolumeDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err } - } - - options := &vpcv1.DeleteVolumeOptions{ - ID: &id, - } - response, err = sess.DeleteVolume(options) - if err != nil { - return fmt.Errorf("[ERROR] Error deleting Instance boot volume : %s\n%s", err, response) - } - _, err = isWaitForInstanceBootVolumeDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) - if err != nil { - return err } d.SetId("") return nil @@ -742,7 +717,7 @@ func isWaitForInstanceBootVolumeDeleted(vol *vpcv1.VpcV1, id string, timeout tim stateConf := &resource.StateChangeConf{ Pending: []string{"retry", isVolumeDeleting}, Target: []string{"done", ""}, - Refresh: isVolumeDeleteRefreshFunc(vol, id), + Refresh: isInstanceBootVolumeDeleteRefreshFunc(vol, id), Timeout: timeout, Delay: 10 * time.Second, MinTimeout: 10 * time.Second, From 4f96a1124a76d4f4bb35ade0883bb1edc04ca8c3 Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Wed, 3 May 2023 11:20:58 +0530 Subject: [PATCH 07/21] Update main.tf --- examples/ibm-is-ng/main.tf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/ibm-is-ng/main.tf b/examples/ibm-is-ng/main.tf index 6fb60b0af0..91264b12a3 100644 --- a/examples/ibm-is-ng/main.tf +++ b/examples/ibm-is-ng/main.tf @@ -1246,8 +1246,7 @@ data "ibm_is_shares" "is_shares" { // vsi boot volume resource "ibm_is_instance_boot_volume" "vol1" { - volume = ibm_is_instance.boot_volume.0.volume_id + volume_id = ibm_is_instance.boot_volume.0.volume_id name = "vol1" profile = "10iops-tier" - zone = var.zone1 } \ No newline at end of file From 3cd6c86e0453440a190d09b9517f1e852a5e80e6 Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Wed, 3 May 2023 11:25:27 +0530 Subject: [PATCH 08/21] review comments --- .../vpc/resource_ibm_is_instance_boot_volume.go | 11 +---------- website/docs/r/is_instance_boot_volume.html.markdown | 7 +++---- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go index fca51a73bb..85d65c77c6 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go @@ -294,16 +294,7 @@ func ResourceIBMISInstanceBootVolumeValidator() *validate.ResourceValidator { ValidateFunctionIdentifier: validate.IntBetween, 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}) + MaxValue: "250"}) validateSchema = append(validateSchema, validate.ValidateSchema{ Identifier: isVolumeIops, diff --git a/website/docs/r/is_instance_boot_volume.html.markdown b/website/docs/r/is_instance_boot_volume.html.markdown index 5342abe18e..e9b6c36422 100644 --- a/website/docs/r/is_instance_boot_volume.html.markdown +++ b/website/docs/r/is_instance_boot_volume.html.markdown @@ -61,7 +61,6 @@ Review the argument references that you can specify for your resource. - `bandwidth` - (Integer) The maximum bandwidth (in megabits per second) for the volume - `delete_all_snapshots` - (Optional, Bool) Deletes all snapshots created from this volume. -- `encryption_key` - (Optional, Forces new resource, String) The key to use for encrypting this volume. - `iops` - (Optional, Integer) The total input/ output operations per second (IOPS) for your storage. This value is required for `custom` storage profiles only. ~> **NOTE:** `iops` value can be upgraded and downgraged if volume is attached to an running virtual server instance. Stopped instances will be started on update of volume. @@ -85,8 +84,7 @@ Review the argument references that you can specify for your resource. - `profile` - (Required, String) The profile to use for this volume. ~> **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. @@ -110,7 +108,8 @@ In addition to all argument reference list, you can access the following attribu - `message` - (String) An explanation of the status reason. - `more_info` - (String) Link to documentation about this status reason - `crn` - (String) The CRN for the volume. - +- `encryption_key` - (String) The key to use for encrypting this volume. +- `resource_group` - (String) The resource group ID for this volume. ## Import The `ibm_is_instance_boot_volume` resource can be imported by using volume ID. From 7e7aa34bd1af05bdeb19b5209263526417ac653f Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Wed, 3 May 2023 11:26:07 +0530 Subject: [PATCH 09/21] Update resource_ibm_is_instance_boot_volume.go --- ibm/service/vpc/resource_ibm_is_instance_boot_volume.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go index 85d65c77c6..d812dbb9d3 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go @@ -508,6 +508,9 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { } options.VolumePatch = volumeNamePatch _, _, err = sess.UpdateVolume(options) + if err != nil { + return err + } _, err = isWaitForInstanceBootVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) if err != nil { return err From bcedc91955d14944bcdc7f6e6862658adfb81187 Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Wed, 3 May 2023 11:26:55 +0530 Subject: [PATCH 10/21] Update is_instance_boot_volume.html.markdown --- website/docs/r/is_instance_boot_volume.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/is_instance_boot_volume.html.markdown b/website/docs/r/is_instance_boot_volume.html.markdown index e9b6c36422..74c0dca20b 100644 --- a/website/docs/r/is_instance_boot_volume.html.markdown +++ b/website/docs/r/is_instance_boot_volume.html.markdown @@ -12,7 +12,7 @@ Provides a resource to manage a boot volume of a VPC virtual server instance. Ma ~> **NOTE:** This is an advanced resource with special caveats. Please read this document in its entirety before using this resource. The `ibm_is_instance_boot_volume` resource behaves differently from normal resources. Terraform does not _create_ this resource but instead attempts to "adopt" it into management. -Every Virtual server instance has a boot volume that can be managed but not destroyed. When Terraform first adopts a instance_boot_volume, +Every Virtual server instance has a boot volume that needs to be managed but not destroyed. When Terraform first adopts a instance_boot_volume, For more information, about VPC, see [getting started with Virtual Private Cloud](https://cloud.ibm.com/docs/vpc?topic=vpc-getting-started). For more information, about updating default security group, see [updating a VPC's default security group rules](https://cloud.ibm.com/docs/vpc?topic=vpc-updating-the-default-security-group&interface=ui). From e611a79e74ec890b1ff2d461c84ba35b1ccd75e1 Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Tue, 16 May 2023 09:44:53 +0530 Subject: [PATCH 11/21] added manager suffix to resource name --- examples/ibm-is-ng/main.tf | 2 +- ibm/provider/provider.go | 4 ++-- .../vpc/resource_ibm_is_instance_boot_volume.go | 16 ++++++++-------- .../docs/r/is_instance_boot_volume.html.markdown | 12 ++++++------ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/examples/ibm-is-ng/main.tf b/examples/ibm-is-ng/main.tf index 91264b12a3..82fb1b8023 100644 --- a/examples/ibm-is-ng/main.tf +++ b/examples/ibm-is-ng/main.tf @@ -1245,7 +1245,7 @@ data "ibm_is_shares" "is_shares" { // vsi boot volume -resource "ibm_is_instance_boot_volume" "vol1" { +resource "ibm_is_instance_boot_volume_manager" "vol1" { volume_id = ibm_is_instance.boot_volume.0.volume_id name = "vol1" profile = "10iops-tier" diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 5f40e2d030..d5a5253997 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -962,7 +962,7 @@ func Provider() *schema.Provider { "ibm_is_flow_log": vpc.ResourceIBMISFlowLog(), "ibm_is_instance": vpc.ResourceIBMISInstance(), "ibm_is_instance_action": vpc.ResourceIBMISInstanceAction(), - "ibm_is_instance_boot_volume": vpc.ResourceIBMISInstanceBootVolume(), + "ibm_is_instance_boot_volume_manager": vpc.ResourceIBMISInstanceBootVolume(), "ibm_is_instance_network_interface": vpc.ResourceIBMIsInstanceNetworkInterface(), "ibm_is_instance_network_interface_floating_ip": vpc.ResourceIBMIsInstanceNetworkInterfaceFloatingIp(), "ibm_is_instance_disk_management": vpc.ResourceIBMISInstanceDiskManagement(), @@ -1362,7 +1362,7 @@ func Validator() validate.ValidatorDict { "ibm_is_instance_template": vpc.ResourceIBMISInstanceTemplateValidator(), "ibm_is_instance": vpc.ResourceIBMISInstanceValidator(), "ibm_is_instance_action": vpc.ResourceIBMISInstanceActionValidator(), - "ibm_is_instance_boot_volume": vpc.ResourceIBMISInstanceBootVolumeValidator(), + "ibm_is_instance_boot_volume_manager": vpc.ResourceIBMISInstanceBootVolumeValidator(), "ibm_is_instance_network_interface": vpc.ResourceIBMIsInstanceNetworkInterfaceValidator(), "ibm_is_instance_disk_management": vpc.ResourceIBMISInstanceDiskManagementValidator(), "ibm_is_instance_volume_attachment": vpc.ResourceIBMISInstanceVolumeAttachmentValidator(), diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go index d812dbb9d3..a59752d726 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go @@ -59,14 +59,14 @@ func ResourceIBMISInstanceBootVolume() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume", isVolumeName), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", isVolumeName), Description: "Volume name", }, isVolumeName: { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume", isVolumeName), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", isVolumeName), Description: "Volume name", }, @@ -74,7 +74,7 @@ func ResourceIBMISInstanceBootVolume() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume", isVolumeProfileName), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", isVolumeProfileName), Description: "Volume profile name", }, @@ -106,7 +106,7 @@ func ResourceIBMISInstanceBootVolume() *schema.Resource { Type: schema.TypeInt, Optional: true, Computed: true, - ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume", isVolumeCapacity), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", isVolumeCapacity), Description: "Volume capacity value", }, isVolumeSourceSnapshot: { @@ -123,7 +123,7 @@ func ResourceIBMISInstanceBootVolume() *schema.Resource { Type: schema.TypeInt, Optional: true, Computed: true, - ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume", isVolumeIops), + ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", isVolumeIops), Description: "IOPS value for the Volume", }, isVolumeCrn: { @@ -202,7 +202,7 @@ func ResourceIBMISInstanceBootVolume() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume", "tags")}, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", "tags")}, Set: flex.ResourceIBMVPCHash, Description: "UserTags for the volume instance", }, @@ -210,7 +210,7 @@ func ResourceIBMISInstanceBootVolume() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume", "accesstag")}, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", "accesstag")}, Set: flex.ResourceIBMVPCHash, Description: "Access management tags for the volume instance", }, @@ -312,7 +312,7 @@ func ResourceIBMISInstanceBootVolumeValidator() *validate.ResourceValidator { MinValueLength: 1, MaxValueLength: 128}) - ibmISVolumeResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_boot_volume", Schema: validateSchema} + ibmISVolumeResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_boot_volume_manager", Schema: validateSchema} return &ibmISVolumeResourceValidator } diff --git a/website/docs/r/is_instance_boot_volume.html.markdown b/website/docs/r/is_instance_boot_volume.html.markdown index 74c0dca20b..63b516d6e8 100644 --- a/website/docs/r/is_instance_boot_volume.html.markdown +++ b/website/docs/r/is_instance_boot_volume.html.markdown @@ -7,10 +7,10 @@ description: |- Manages IBM volume. --- -# ibm_is_instance_boot_volume +# ibm_is_instance_boot_volume_manager Provides a resource to manage a boot volume of a VPC virtual server instance. Manage the boot volume of a VPC virtual server instance created alongwith the instance creation with this resource. -~> **NOTE:** This is an advanced resource with special caveats. Please read this document in its entirety before using this resource. The `ibm_is_instance_boot_volume` resource behaves differently from normal resources. Terraform does not _create_ this resource but instead attempts to "adopt" it into management. +~> **NOTE:** This is an advanced resource with special caveats. Please read this document in its entirety before using this resource. The `ibm_is_instance_boot_volume_manager` resource behaves differently from normal resources. Terraform does not _create_ this resource but instead attempts to "adopt" it into management. Every Virtual server instance has a boot volume that needs to be managed but not destroyed. When Terraform first adopts a instance_boot_volume, @@ -31,7 +31,7 @@ provider "ibm" { The following example creates a volume with 10 IOPs tier. ```terraform -resource "ibm_is_instance_boot_volume" "example" { +resource "ibm_is_instance_boot_volume_manager" "example" { name = "example-volume" profile = "10iops-tier" zone = "us-south-1" @@ -39,7 +39,7 @@ resource "ibm_is_instance_boot_volume" "example" { ``` ## Timeouts -The `ibm_is_instance_boot_volume` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: +The `ibm_is_instance_boot_volume_manager` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: - **create** - (Default 10 minutes) Used for creating instance. - **delete** - (Default 10 minutes) Used for deleting instance. @@ -111,10 +111,10 @@ In addition to all argument reference list, you can access the following attribu - `encryption_key` - (String) The key to use for encrypting this volume. - `resource_group` - (String) The resource group ID for this volume. ## Import -The `ibm_is_instance_boot_volume` resource can be imported by using volume ID. +The `ibm_is_instance_boot_volume_manager` resource can be imported by using volume ID. **Example** ``` -$ terraform import ibm_is_instance_boot_volume.example d7bec597-4726-451f-8a63-e62e6f19c32c +$ terraform import ibm_is_instance_boot_volume_manager.example d7bec597-4726-451f-8a63-e62e6f19c32c ``` From 60f822e5407dd2ba2920f24238f54a3ba48e977c Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Thu, 18 May 2023 10:09:02 +0530 Subject: [PATCH 12/21] changed file names --- ..._volume.go => resource_ibm_is_instance_boot_volume_manager.go} | 0 ...st.go => resource_ibm_is_instance_boot_volume_manager_test.go} | 0 ...tml.markdown => is_instance_boot_volume_manager.html.markdown} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename ibm/service/vpc/{resource_ibm_is_instance_boot_volume.go => resource_ibm_is_instance_boot_volume_manager.go} (100%) rename ibm/service/vpc/{resource_ibm_is_instance_boot_volume_test.go => resource_ibm_is_instance_boot_volume_manager_test.go} (100%) rename website/docs/r/{is_instance_boot_volume.html.markdown => is_instance_boot_volume_manager.html.markdown} (100%) diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go similarity index 100% rename from ibm/service/vpc/resource_ibm_is_instance_boot_volume.go rename to ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_test.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go similarity index 100% rename from ibm/service/vpc/resource_ibm_is_instance_boot_volume_test.go rename to ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go diff --git a/website/docs/r/is_instance_boot_volume.html.markdown b/website/docs/r/is_instance_boot_volume_manager.html.markdown similarity index 100% rename from website/docs/r/is_instance_boot_volume.html.markdown rename to website/docs/r/is_instance_boot_volume_manager.html.markdown From 8a4db7d3d7a6b3a0666f31d27b48a784c1639479 Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Fri, 19 May 2023 14:56:29 +0530 Subject: [PATCH 13/21] changed file refrences --- ibm/provider/provider.go | 4 +- ...rce_ibm_is_instance_boot_volume_manager.go | 70 ++-- ...bm_is_instance_boot_volume_manager_test.go | 389 +++++++----------- 3 files changed, 184 insertions(+), 279 deletions(-) diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 8eccfdb9c4..d8f79599c1 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -974,7 +974,7 @@ func Provider() *schema.Provider { "ibm_is_flow_log": vpc.ResourceIBMISFlowLog(), "ibm_is_instance": vpc.ResourceIBMISInstance(), "ibm_is_instance_action": vpc.ResourceIBMISInstanceAction(), - "ibm_is_instance_boot_volume_manager": vpc.ResourceIBMISInstanceBootVolume(), + "ibm_is_instance_boot_volume_manager": vpc.ResourceIBMISInstanceBootVolumeManager(), "ibm_is_instance_network_interface": vpc.ResourceIBMIsInstanceNetworkInterface(), "ibm_is_instance_network_interface_floating_ip": vpc.ResourceIBMIsInstanceNetworkInterfaceFloatingIp(), "ibm_is_instance_disk_management": vpc.ResourceIBMISInstanceDiskManagement(), @@ -1381,7 +1381,7 @@ func Validator() validate.ValidatorDict { "ibm_is_instance_template": vpc.ResourceIBMISInstanceTemplateValidator(), "ibm_is_instance": vpc.ResourceIBMISInstanceValidator(), "ibm_is_instance_action": vpc.ResourceIBMISInstanceActionValidator(), - "ibm_is_instance_boot_volume_manager": vpc.ResourceIBMISInstanceBootVolumeValidator(), + "ibm_is_instance_boot_volume_manager": vpc.ResourceIBMISInstanceBootVolumeManagerValidator(), "ibm_is_instance_network_interface": vpc.ResourceIBMIsInstanceNetworkInterfaceValidator(), "ibm_is_instance_disk_management": vpc.ResourceIBMISInstanceDiskManagementValidator(), "ibm_is_instance_volume_attachment": vpc.ResourceIBMISInstanceVolumeAttachmentValidator(), diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go index a59752d726..91e298649e 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go @@ -20,16 +20,16 @@ import ( ) const ( - isInstanceBootVolumeDelete = "delete" + isInstanceBootVolumeManagerDelete = "delete" ) -func ResourceIBMISInstanceBootVolume() *schema.Resource { +func ResourceIBMISInstanceBootVolumeManager() *schema.Resource { return &schema.Resource{ - Create: resourceIBMISInstanceBootVolumeCreate, - Read: resourceIBMISInstanceBootVolumeRead, - Update: resourceIBMISInstanceBootVolumeUpdate, - Delete: resourceIBMISInstanceBootVolumeDelete, - Exists: resourceIBMISInstanceBootVolumeExists, + Create: resourceIBMISInstanceBootVolumeManagerCreate, + Read: resourceIBMISInstanceBootVolumeManagerRead, + Update: resourceIBMISInstanceBootVolumeManagerUpdate, + Delete: resourceIBMISInstanceBootVolumeManagerDelete, + Exists: resourceIBMISInstanceBootVolumeManagerExists, Importer: &schema.ResourceImporter{}, Timeouts: &schema.ResourceTimeout{ @@ -90,7 +90,7 @@ func ResourceIBMISInstanceBootVolume() *schema.Resource { Description: "Volume encryption key info", }, - isInstanceBootVolumeDelete: { + isInstanceBootVolumeManagerDelete: { Type: schema.TypeBool, Optional: true, Description: "Volume encryption key info", @@ -254,7 +254,7 @@ func ResourceIBMISInstanceBootVolume() *schema.Resource { } } -func ResourceIBMISInstanceBootVolumeValidator() *validate.ResourceValidator { +func ResourceIBMISInstanceBootVolumeManagerValidator() *validate.ResourceValidator { validateSchema := make([]validate.ValidateSchema, 0) validateSchema = append(validateSchema, @@ -316,19 +316,19 @@ func ResourceIBMISInstanceBootVolumeValidator() *validate.ResourceValidator { return &ibmISVolumeResourceValidator } -func resourceIBMISInstanceBootVolumeCreate(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISInstanceBootVolumeManagerCreate(d *schema.ResourceData, meta interface{}) error { volId := d.Get(isInstanceBootVolumeId).(string) d.SetId(volId) - err := resourceIBMISInstanceBootVolumeRead(d, meta) + err := resourceIBMISInstanceBootVolumeManagerRead(d, meta) if err != nil { return err } - return resourceIBMISInstanceBootVolumeUpdate(d, meta) + return resourceIBMISInstanceBootVolumeManagerUpdate(d, meta) } -func resourceIBMISInstanceBootVolumeRead(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISInstanceBootVolumeManagerRead(d *schema.ResourceData, meta interface{}) error { id := d.Id() err := instancebootvolGet(d, meta, id) @@ -432,12 +432,12 @@ func instancebootvolGet(d *schema.ResourceData, meta interface{}, id string) err return nil } -func resourceIBMISInstanceBootVolumeUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISInstanceBootVolumeManagerUpdate(d *schema.ResourceData, meta interface{}) error { err := instancebootvolUpdate(d, meta) if err != nil { return err } - return resourceIBMISInstanceBootVolumeRead(d, meta) + return resourceIBMISInstanceBootVolumeManagerRead(d, meta) } func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { @@ -470,7 +470,7 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { } vol, response, err := sess.GetVolume(options) if err != nil { - return fmt.Errorf("Error getting Instance boot volume : %s\n%s", err, response) + return fmt.Errorf("[ERROR]Error getting Instance boot volume : %s\n%s", err, response) } oldList, newList := d.GetChange(isVolumeAccessTags) @@ -490,7 +490,7 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { d.SetId("") return nil } - return fmt.Errorf("Error getting Instance boot volume (%s): %s\n%s", id, err, response) + return fmt.Errorf("[ERROR] Error getting Instance boot volume (%s): %s\n%s", id, err, response) } eTag := response.Headers.Get("ETag") options := &vpcv1.UpdateVolumeOptions{ @@ -507,11 +507,12 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("[ERROR] Error calling asPatch for volumeNamePatch in Instance boot volume : %s", err) } options.VolumePatch = volumeNamePatch - _, _, err = sess.UpdateVolume(options) + _, response, err = sess.UpdateVolume(options) + eTag = response.Headers.Get("ETag") if err != nil { return err } - _, err = isWaitForInstanceBootVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + _, err = isWaitForInstanceBootVolumeManagerAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), &eTag) if err != nil { return err } @@ -575,7 +576,7 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { } options.VolumePatch = volumeProfilePatch _, response, err = sess.UpdateVolume(options) - _, err = isWaitForInstanceBootVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + _, err = isWaitForInstanceBootVolumeManagerAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), &eTag) if err != nil { return err } @@ -634,7 +635,7 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { if err != nil { return fmt.Errorf("[ERROR] Error updating Instance boot volume: %s\n%s", err, response) } - _, err = isWaitForInstanceBootVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + _, err = isWaitForInstanceBootVolumeManagerAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), &eTag) if err != nil { return err } @@ -661,15 +662,15 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { volumeNamePatchModel.UserTags = userTagsArray volumeNamePatch, err := volumeNamePatchModel.AsPatch() if err != nil { - return fmt.Errorf("Error calling asPatch for volumeNamePatch in Instance boot volume: %s", err) + return fmt.Errorf("[ERROR] Error calling asPatch for volumeNamePatch in Instance boot volume: %s", err) } options.IfMatch = &eTag options.VolumePatch = volumeNamePatch _, response, err := sess.UpdateVolume(options) if err != nil { - return fmt.Errorf("Error updating Instance boot volume : %s\n%s", err, response) + return fmt.Errorf("[ERROR] Error updating Instance boot volume : %s\n%s", err, response) } - _, err = isWaitForInstanceBootVolumeAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate)) + _, err = isWaitForInstanceBootVolumeManagerAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), &eTag) if err != nil { return err } @@ -680,10 +681,10 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { return nil } -func resourceIBMISInstanceBootVolumeDelete(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISInstanceBootVolumeManagerDelete(d *schema.ResourceData, meta interface{}) error { id := d.Id() // check if force delete is true - if d.Get(isInstanceBootVolumeDelete).(bool) { + if d.Get(isInstanceBootVolumeManagerDelete).(bool) { sess, err := vpcClient(meta) if err != nil { return err @@ -696,7 +697,7 @@ func resourceIBMISInstanceBootVolumeDelete(d *schema.ResourceData, meta interfac if err != nil { return fmt.Errorf("[ERROR] Error deleting Volume : %s\n%s", err, response) } - _, err = isWaitForInstanceBootVolumeDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) + _, err = isWaitForInstanceBootVolumeManagerDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) if err != nil { return err } @@ -705,13 +706,13 @@ func resourceIBMISInstanceBootVolumeDelete(d *schema.ResourceData, meta interfac return nil } -func isWaitForInstanceBootVolumeDeleted(vol *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { +func isWaitForInstanceBootVolumeManagerDeleted(vol *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { log.Printf("Waiting for (%s) to be deleted.", id) stateConf := &resource.StateChangeConf{ Pending: []string{"retry", isVolumeDeleting}, Target: []string{"done", ""}, - Refresh: isInstanceBootVolumeDeleteRefreshFunc(vol, id), + Refresh: isInstanceBootVolumeManagerDeleteRefreshFunc(vol, id), Timeout: timeout, Delay: 10 * time.Second, MinTimeout: 10 * time.Second, @@ -720,7 +721,7 @@ func isWaitForInstanceBootVolumeDeleted(vol *vpcv1.VpcV1, id string, timeout tim return stateConf.WaitForState() } -func isInstanceBootVolumeDeleteRefreshFunc(vol *vpcv1.VpcV1, id string) resource.StateRefreshFunc { +func isInstanceBootVolumeManagerDeleteRefreshFunc(vol *vpcv1.VpcV1, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { volgetoptions := &vpcv1.GetVolumeOptions{ ID: &id, @@ -736,7 +737,7 @@ func isInstanceBootVolumeDeleteRefreshFunc(vol *vpcv1.VpcV1, id string) resource } } -func resourceIBMISInstanceBootVolumeExists(d *schema.ResourceData, meta interface{}) (bool, error) { +func resourceIBMISInstanceBootVolumeManagerExists(d *schema.ResourceData, meta interface{}) (bool, error) { id := d.Id() @@ -762,13 +763,13 @@ func instancebootvolExists(d *schema.ResourceData, meta interface{}, id string) return true, nil } -func isWaitForInstanceBootVolumeAvailable(client *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { +func isWaitForInstanceBootVolumeManagerAvailable(client *vpcv1.VpcV1, id string, timeout time.Duration, eTag *string) (interface{}, error) { log.Printf("Waiting for Instance boot volume (%s) to be available.", id) stateConf := &resource.StateChangeConf{ Pending: []string{"retry", isVolumeProvisioning}, Target: []string{isVolumeProvisioningDone, ""}, - Refresh: isVolumeRefreshFunc(client, id), + Refresh: isInstanceBootVolumeManagerRefreshFunc(client, id, eTag), Timeout: timeout, Delay: 10 * time.Second, MinTimeout: 10 * time.Second, @@ -777,7 +778,7 @@ func isWaitForInstanceBootVolumeAvailable(client *vpcv1.VpcV1, id string, timeou return stateConf.WaitForState() } -func isInstanceBootVolumeRefreshFunc(client *vpcv1.VpcV1, id string) resource.StateRefreshFunc { +func isInstanceBootVolumeManagerRefreshFunc(client *vpcv1.VpcV1, id string, eTag *string) resource.StateRefreshFunc { return func() (interface{}, string, error) { volgetoptions := &vpcv1.GetVolumeOptions{ ID: &id, @@ -790,6 +791,7 @@ func isInstanceBootVolumeRefreshFunc(client *vpcv1.VpcV1, id string) resource.St if *vol.Status == "available" { return vol, isVolumeProvisioningDone, nil } + *eTag = response.Headers.Get("ETag") return vol, isVolumeProvisioning, nil } diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go index 34a77505e7..781c0e3f7b 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go @@ -18,67 +18,145 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -func TestAccIBMISInstanceBootVolume_basic(t *testing.T) { +func TestAccIBMISInstanceBootVolumeManager_basic(t *testing.T) { var vol string - name := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) - name1 := fmt.Sprintf("tf-vol-upd-%d", acctest.RandIntRange(10, 100)) - resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVolumeDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISVolumeConfig(name), + Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), - resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "name", name), - ), - }, - - { - Config: testAccCheckIBMISVolumeConfig(name1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), - resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "name", name1), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), ), }, }, }) } -func TestAccIBMISInstanceBootVolume_snapshot(t *testing.T) { +func TestAccIBMISInstanceBootVolumeManager_tag_name_update(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)) + name1 := fmt.Sprintf("tfbootvoluat-%d", acctest.RandIntRange(10, 100)) + name2 := fmt.Sprintf("tfbootvoluat-%d", acctest.RandIntRange(10, 100)) + tag1 := "env:prod" + tag2 := "boot:unattached" + tag3 := "delete:false" 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), + Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + ), + }, + { + Config: testAccCheckIBMISInstanceBootVolumeManagerNameTagUpdateConfig(name1, tag1, tag2, ""), 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.#"), + testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.boot", "name", name1), + ), + }, + { + Config: testAccCheckIBMISInstanceBootVolumeManagerNameTagUpdateConfig(name2, tag1, tag2, tag3), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "name", volname), + "ibm_is_instance_boot_volume_manager.boot", "name", name2), ), }, }, }) } -func TestAccIBMISInstanceBootVolumeUsertag_basic(t *testing.T) { +func TestAccIBMISInstanceBootVolumeManagerUsertag_basic(t *testing.T) { var vol string name := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) tagname := fmt.Sprintf("tfusertag%d", acctest.RandIntRange(10, 100)) @@ -92,35 +170,35 @@ func TestAccIBMISInstanceBootVolumeUsertag_basic(t *testing.T) { resource.TestStep{ Config: testAccCheckIBMISVolumeUsertagConfig(name, tagname), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "name", name), + "ibm_is_instance_boot_volume_manager.boot", "name", name), resource.TestCheckResourceAttrSet( - "ibm_is_volume.storage", "tags.#"), + "ibm_is_instance_boot_volume_manager.boot", "tags.#"), resource.TestCheckResourceAttrSet( - "ibm_is_volume.storage", "tags.0"), + "ibm_is_instance_boot_volume_manager.boot", "tags.0"), resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "tags.0", tagname), + "ibm_is_instance_boot_volume_manager.boot", "tags.0", tagname), ), }, resource.TestStep{ Config: testAccCheckIBMISVolumeUsertagConfig(name, tagnameupdate), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), resource.TestCheckResourceAttrSet( - "ibm_is_volume.storage", "tags.#"), + "ibm_is_instance_boot_volume_manager.boot", "tags.#"), resource.TestCheckResourceAttrSet( - "ibm_is_volume.storage", "tags.0"), + "ibm_is_instance_boot_volume_manager.boot", "tags.0"), resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "tags.0", tagnameupdate), + "ibm_is_instance_boot_volume_manager.boot", "tags.0", tagnameupdate), ), }, }, }) } -func TestAccIBMISInstanceBootVolumeUpdateCustom_basic(t *testing.T) { +func TestAccIBMISInstanceBootVolumeManagerDelete_basic(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)) @@ -141,160 +219,29 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE { Config: testAccCheckIBMISVolumeCustomConfig(vpcname, subnetname, sshname, publicKey, name, volName, iops1), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "name", volName), + "ibm_is_instance_boot_volume_manager.boot", "name", volName), resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "iops", fmt.Sprintf("%d", iops1)), + "ibm_is_instance_boot_volume_manager.boot", "iops", fmt.Sprintf("%d", iops1)), ), }, { Config: testAccCheckIBMISVolumeCustomConfig(vpcname, subnetname, sshname, publicKey, name, volName, iops2), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), - resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "name", volName), - resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "iops", fmt.Sprintf("%d", iops2)), - ), - }, - }, - }) -} - -func TestAccIBMISInstanceBootVolumeUpdateTier_basic(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)) - profileName1 := "general-purpose" - profileName2 := "5iops-tier" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMISVolumeDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISVolumeTierConfig(vpcname, subnetname, sshname, publicKey, name, volName, profileName1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), - resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "name", volName), - resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "profile", profileName1), - ), - }, - - { - Config: testAccCheckIBMISVolumeTierConfig(vpcname, subnetname, sshname, publicKey, name, volName, profileName2), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), + testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "name", volName), + "ibm_is_instance_boot_volume_manager.boot", "name", volName), resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "profile", profileName2), + "ibm_is_instance_boot_volume_manager.boot", "iops", fmt.Sprintf("%d", iops2)), ), }, }, }) } -func TestAccIBMISInstanceBootVolumeUpdateCapacity_basic(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)) - capacity1 := int64(100) - capacity2 := int64(120) - - resource.Test(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMISVolumeDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISVolumeCapacityConfig(vpcname, subnetname, sshname, publicKey, name, volName, capacity1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), - resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "name", volName), - resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "capacity", fmt.Sprintf("%d", capacity1)), - ), - }, - - { - Config: testAccCheckIBMISVolumeCapacityConfig(vpcname, subnetname, sshname, publicKey, name, volName, capacity2), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_volume.storage", vol), - resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "name", volName), - resource.TestCheckResourceAttr( - "ibm_is_volume.storage", "capacity", fmt.Sprintf("%d", capacity2)), - ), - }, - }, - }) -} - -func TestAccIBMISInstanceBootVolumeAttachmentDelete_basic(t *testing.T) { - var vol string - insname := fmt.Sprintf("tf-ins-%d", acctest.RandIntRange(10, 100)) - initialVolumeCapacityArray := fmt.Sprintf("[%d, %d]", 10, 20) - finalVolumeCapacityArray := fmt.Sprintf("[%d]", 10) - vpcname := fmt.Sprintf("tf-vpc-%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)) - resource.Test(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMISVolumeDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckIBMISVolumeAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, initialVolumeCapacityArray), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_volume.storage.0", vol), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", insname), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "volume_attachments.#", "3"), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "volumes.#", "2"), - ), - }, - - { - Config: testAccCheckIBMISVolumeAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, finalVolumeCapacityArray), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_volume.storage.0", vol), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "name", insname), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "volume_attachments.#", "2"), - resource.TestCheckResourceAttr( - "ibm_is_instance.testacc_instance", "volumes.#", "1"), - ), - }, - }, - }) -} - -func testAccCheckIBMISInstanceBootVolumeDestroy(s *terraform.State) error { +func testAccCheckIBMISInstanceBootVolumeManagerDestroy(s *terraform.State) error { sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { @@ -315,7 +262,7 @@ func testAccCheckIBMISInstanceBootVolumeDestroy(s *terraform.State) error { return nil } -func testAccCheckIBMISInstanceBootVolumeExists(n, volID string) resource.TestCheckFunc { +func testAccCheckIBMISInstanceBootVolumeManagerExists(n, volID string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -340,61 +287,29 @@ func testAccCheckIBMISInstanceBootVolumeExists(n, volID string) resource.TestChe } } -func testAccCheckIBMISInstanceBootVolumeConfig(name string) string { +func testAccCheckIBMISInstanceBootVolumeManagerConfig() string { return fmt.Sprintf( ` - resource "ibm_is_volume" "storage"{ - name = "%s" - profile = "10iops-tier" - zone = "us-south-1" - # capacity= 200 + resource "ibm_is_instance_boot_volume_manager" "boot"{ + volume_id = "%s" } -`, name) +`, acc.VSIUnattachedBootVolumeID) } -func testAccCheckIBMISInstanceBootVolumeCustomConfig(vpcname, subnetname, sshname, publicKey, name, volName string, iops int64) string { +func testAccCheckIBMISInstanceBootVolumeManagerNameTagUpdateConfig(name, tag1, tag2, tag3 string) string { return fmt.Sprintf( ` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - total_ipv4_address_count = 16 - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" + resource "ibm_is_instance_boot_volume_manager" "boot"{ + volume_id = "%s" + name = "%s" + tags = "%s" == "" ? ["%s", "%s"] : ["%s", "%s", "%s"] } - resource "ibm_is_volume" "storage"{ - name = "%s" - profile = "custom" - zone = "%s" - iops = %d - } - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - volumes = [ibm_is_volume.storage.id] - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - } - -`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, volName, acc.ISZoneName, iops, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) +`, acc.VSIUnattachedBootVolumeID, name, tag3, tag1, tag2, tag1, tag2, tag3) } -func testAccCheckIBMISInstanceBootVolumeTierConfig(vpcname, subnetname, sshname, publicKey, name, volName, profileName string) string { +func testAccCheckIBMISInstanceBootVolumeManagerTierConfig(vpcname, subnetname, sshname, publicKey, name, volName, profileName string) string { return fmt.Sprintf( ` resource "ibm_is_vpc" "testacc_vpc" { @@ -421,7 +336,7 @@ func testAccCheckIBMISInstanceBootVolumeTierConfig(vpcname, subnetname, sshname, name = "%s" image = "%s" profile = "%s" - volumes = [ibm_is_volume.storage.id] + volumes = [ibm_is_instance_boot_volume_manager.boot.id] primary_network_interface { subnet = ibm_is_subnet.testacc_subnet.id } @@ -434,7 +349,7 @@ func testAccCheckIBMISInstanceBootVolumeTierConfig(vpcname, subnetname, sshname, } -func testAccCheckIBMISInstanceBootVolumeAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, capacityArray string) string { +func testAccCheckIBMISInstanceBootVolumeManagerAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, capacityArray string) string { return fmt.Sprintf( ` variable "vsi_vol_size" { @@ -470,7 +385,7 @@ func testAccCheckIBMISInstanceBootVolumeAttachmentDeleteConfig(vpcname, subnetna name = "%s" image = "%s" profile = "%s" - volumes = ibm_is_volume.storage[*].id + volumes = ibm_is_instance_boot_volume_manager.boot[*].id primary_network_interface { subnet = ibm_is_subnet.testacc_subnet.id } @@ -482,7 +397,7 @@ func testAccCheckIBMISInstanceBootVolumeAttachmentDeleteConfig(vpcname, subnetna } -func testAccCheckIBMISInstanceBootVolumeCapacityConfig(vpcname, subnetname, sshname, publicKey, name, volName string, capacity int64) string { +func testAccCheckIBMISInstanceBootVolumeManagerCapacityConfig(vpcname, subnetname, sshname, publicKey, name, volName string, capacity int64) string { return fmt.Sprintf( ` resource "ibm_is_vpc" "testacc_vpc" { @@ -510,7 +425,7 @@ func testAccCheckIBMISInstanceBootVolumeCapacityConfig(vpcname, subnetname, sshn name = "%s" image = "%s" profile = "%s" - volumes = [ibm_is_volume.storage.id] + volumes = [ibm_is_instance_boot_volume_manager.boot.id] primary_network_interface { subnet = ibm_is_subnet.testacc_subnet.id } @@ -523,7 +438,7 @@ func testAccCheckIBMISInstanceBootVolumeCapacityConfig(vpcname, subnetname, sshn } -func testAccCheckIBMISInstanceBootVolumeUsertagConfig(name, usertag string) string { +func testAccCheckIBMISInstanceBootVolumeManagerUsertagConfig(name, usertag string) string { return fmt.Sprintf( ` resource "ibm_is_volume" "storage"{ @@ -536,15 +451,3 @@ func testAccCheckIBMISInstanceBootVolumeUsertagConfig(name, usertag string) stri `, name, usertag) } - -func testAccCheckIBMISInstanceBootVolumeConfigSnapshot(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) -} From d26eea3b04b7ad3728b21c421052eea72f737ffe Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Fri, 26 May 2023 09:44:47 +0530 Subject: [PATCH 14/21] Update is_instance_boot_volume_manager.html.markdown --- ..._instance_boot_volume_manager.html.markdown | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/website/docs/r/is_instance_boot_volume_manager.html.markdown b/website/docs/r/is_instance_boot_volume_manager.html.markdown index 63b516d6e8..b108f80ec6 100644 --- a/website/docs/r/is_instance_boot_volume_manager.html.markdown +++ b/website/docs/r/is_instance_boot_volume_manager.html.markdown @@ -2,9 +2,9 @@ subcategory: "VPC infrastructure" layout: "ibm" -page_title: "IBM : instance_boot_volume" +page_title: "IBM : instance_boot_volume_manager" description: |- - Manages IBM volume. + Manages IBM instance boot volume. --- # ibm_is_instance_boot_volume_manager @@ -12,7 +12,7 @@ Provides a resource to manage a boot volume of a VPC virtual server instance. Ma ~> **NOTE:** This is an advanced resource with special caveats. Please read this document in its entirety before using this resource. The `ibm_is_instance_boot_volume_manager` resource behaves differently from normal resources. Terraform does not _create_ this resource but instead attempts to "adopt" it into management. -Every Virtual server instance has a boot volume that needs to be managed but not destroyed. When Terraform first adopts a instance_boot_volume, +Every Virtual server instance has a boot volume that needs to be managed but not destroyed. When Terraform first adopts a instance_boot_volume_manager, For more information, about VPC, see [getting started with Virtual Private Cloud](https://cloud.ibm.com/docs/vpc?topic=vpc-getting-started). For more information, about updating default security group, see [updating a VPC's default security group rules](https://cloud.ibm.com/docs/vpc?topic=vpc-updating-the-default-security-group&interface=ui). @@ -28,13 +28,13 @@ provider "ibm" { ``` ## Example usage -The following example creates a volume with 10 IOPs tier. +The following example manages a boot volume with 10 IOPs tier. ```terraform resource "ibm_is_instance_boot_volume_manager" "example" { - name = "example-volume" - profile = "10iops-tier" - zone = "us-south-1" + volume_id = "r006-10cc2ee8-f395-47a1-b043-4e7a855a6dd0" + name = "example-volume" + profile = "10iops-tier" } ``` @@ -87,7 +87,7 @@ Review the argument references that you can specify for your resource. - `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. +- `volume_id` - (Required, Forces new resource, String) The volume id of the volume from boot volume. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. @@ -110,6 +110,8 @@ In addition to all argument reference list, you can access the following attribu - `crn` - (String) The CRN for the volume. - `encryption_key` - (String) The key to use for encrypting this volume. - `resource_group` - (String) The resource group ID for this volume. +- `zone` - (String) The location of the volume. + ## Import The `ibm_is_instance_boot_volume_manager` resource can be imported by using volume ID. From 24a3df2d5502d370e04749c67a681fe4834acb83 Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Fri, 26 May 2023 09:46:00 +0530 Subject: [PATCH 15/21] removed --- ibm/service/vpc/data_source_ibm_is_instance_template.go | 4 ---- ibm/service/vpc/data_source_ibm_is_lb_profile.go | 2 -- ibm/service/vpc/resource_ibm_is_instance_template.go | 2 -- 3 files changed, 8 deletions(-) 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 e725cab0ba..7412407c72 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_template.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_template.go @@ -508,7 +508,6 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso } if instance.PrimaryNetworkInterface != nil { - log.Printf("[INFO] UJJK PNI") interfaceList := make([]map[string]interface{}, 0) currentPrimNic := map[string]interface{}{} currentPrimNic[isInstanceTemplateNicName] = *instance.PrimaryNetworkInterface.Name @@ -519,7 +518,6 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso switch reflect.TypeOf(primaryipIntf).String() { case "*vpcv1.NetworkInterfaceIPPrototype": { - log.Printf("[INFO] UJJK NetworkInterfaceIPPrototype") primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototype) if primaryip.Address != nil { currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = *primaryip.Address @@ -531,7 +529,6 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso } case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext": { - log.Printf("[INFO] UJJK NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext") primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPPrototypeNetworkInterfaceContext) if primaryip.Address != nil { currentPrimNic[isInstanceTemplateNicPrimaryIpv4Address] = *primaryip.Address @@ -540,7 +537,6 @@ func dataSourceIBMISInstanceTemplateRead(context context.Context, d *schema.Reso } case "*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity": { - log.Printf("[INFO] UJJK NetworkInterfaceIPPrototypeReservedIPIdentity") primaryip := primaryipIntf.(*vpcv1.NetworkInterfaceIPPrototypeReservedIPIdentity) if primaryip.ID != nil { currentPrimIp[isInstanceTemplateNicReservedIpId] = *primaryip.ID diff --git a/ibm/service/vpc/data_source_ibm_is_lb_profile.go b/ibm/service/vpc/data_source_ibm_is_lb_profile.go index 9d166645d3..d7fa95900d 100644 --- a/ibm/service/vpc/data_source_ibm_is_lb_profile.go +++ b/ibm/service/vpc/data_source_ibm_is_lb_profile.go @@ -76,10 +76,8 @@ func dataSourceIBMISLbProfileRead(context context.Context, d *schema.ResourceDat d.Set("name", *lbProfile.Name) d.Set("href", *lbProfile.Href) d.Set("family", *lbProfile.Family) - log.Printf("[INFO] UJJK lbprofile udp %v", lbProfile.UDPSupported) if lbProfile.UDPSupported != nil { udpSupport := lbProfile.UDPSupported - log.Printf("[INFO] UJJK lbprofile udp %s", reflect.TypeOf(udpSupport).String()) switch reflect.TypeOf(udpSupport).String() { case "*vpcv1.LoadBalancerProfileUDPSupportedFixed": diff --git a/ibm/service/vpc/resource_ibm_is_instance_template.go b/ibm/service/vpc/resource_ibm_is_instance_template.go index 9ac2e29abe..a894ed362f 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_template.go +++ b/ibm/service/vpc/resource_ibm_is_instance_template.go @@ -1042,7 +1042,6 @@ func instanceTemplateCreateByCatalogOffering(d *schema.ResourceData, meta interf // var reservedipautodeleteok interface{} if v, ok := primip[isInstanceTemplateNicReservedIpAutoDelete].(bool); ok && v { - log.Printf("[INFO] UJJK isInstanceTemplateNicReservedIpAutoDelete is v is %t and okay is %t", v, ok) reservedIpAutoDelete = primip[isInstanceTemplateNicReservedIpAutoDelete].(bool) okAuto = true } @@ -1465,7 +1464,6 @@ func instanceTemplateCreate(d *schema.ResourceData, meta interface{}, profile, n // var reservedipautodeleteok interface{} if v, ok := primip[isInstanceTemplateNicReservedIpAutoDelete].(bool); ok && v { - log.Printf("[INFO] UJJK isInstanceTemplateNicReservedIpAutoDelete is v is %t and okay is %t", v, ok) reservedIpAutoDelete = primip[isInstanceTemplateNicReservedIpAutoDelete].(bool) okAuto = true } From 38bff611b17b6e57e6508c053629fae1b2829aff Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Fri, 26 May 2023 10:01:55 +0530 Subject: [PATCH 16/21] updated --- ibm/service/vpc/data_source_ibm_is_instance_template.go | 1 - ibm/service/vpc/data_source_ibm_is_lb_profile.go | 1 - ibm/service/vpc/resource_ibm_is_instance_template.go | 1 - 3 files changed, 3 deletions(-) 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 7412407c72..03d71f64d7 100644 --- a/ibm/service/vpc/data_source_ibm_is_instance_template.go +++ b/ibm/service/vpc/data_source_ibm_is_instance_template.go @@ -6,7 +6,6 @@ package vpc import ( "context" "fmt" - "log" "reflect" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" diff --git a/ibm/service/vpc/data_source_ibm_is_lb_profile.go b/ibm/service/vpc/data_source_ibm_is_lb_profile.go index d7fa95900d..bafcd9d361 100644 --- a/ibm/service/vpc/data_source_ibm_is_lb_profile.go +++ b/ibm/service/vpc/data_source_ibm_is_lb_profile.go @@ -6,7 +6,6 @@ package vpc import ( "context" "fmt" - "log" "reflect" "github.com/IBM/vpc-go-sdk/vpcv1" diff --git a/ibm/service/vpc/resource_ibm_is_instance_template.go b/ibm/service/vpc/resource_ibm_is_instance_template.go index a894ed362f..3baa5b8752 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_template.go +++ b/ibm/service/vpc/resource_ibm_is_instance_template.go @@ -6,7 +6,6 @@ package vpc import ( "context" "fmt" - "log" "reflect" "strings" From 09485828f1d1d71002febe4913ed20933664cb52 Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Fri, 26 May 2023 10:35:31 +0530 Subject: [PATCH 17/21] updated tests and docs --- ...bm_is_instance_boot_volume_manager_test.go | 475 ++++++++++++++++-- ...instance_boot_volume_manager.html.markdown | 4 +- 2 files changed, 448 insertions(+), 31 deletions(-) diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go index 781c0e3f7b..63e4af3a70 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go @@ -55,10 +55,8 @@ func TestAccIBMISInstanceBootVolumeManager_basic(t *testing.T) { }) } -func TestAccIBMISInstanceBootVolumeManager_tag_name_update(t *testing.T) { +func TestAccIBMISInstanceBootVolumeManager_capacity_update(t *testing.T) { var vol string - name1 := fmt.Sprintf("tfbootvoluat-%d", acctest.RandIntRange(10, 100)) - name2 := fmt.Sprintf("tfbootvoluat-%d", acctest.RandIntRange(10, 100)) tag1 := "env:prod" tag2 := "boot:unattached" tag3 := "delete:false" @@ -94,7 +92,7 @@ func TestAccIBMISInstanceBootVolumeManager_tag_name_update(t *testing.T) { ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerNameTagUpdateConfig(name1, tag1, tag2, ""), + Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, ""), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), resource.TestCheckResourceAttrSet( @@ -119,12 +117,172 @@ func TestAccIBMISInstanceBootVolumeManager_tag_name_update(t *testing.T) { "ibm_is_instance_boot_volume_manager.boot", "zone"), resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), - resource.TestCheckResourceAttr( - "ibm_is_instance_boot_volume_manager.boot", "name", name1), ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerNameTagUpdateConfig(name2, tag1, tag2, tag3), + Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, tag3), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), + ), + }, + }, + }) +} +func TestAccIBMISInstanceBootVolumeManager_iops_update(t *testing.T) { + var vol string + tag1 := "env:prod" + tag2 := "boot:unattached" + tag3 := "delete:false" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVolumeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + ), + }, + { + Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, ""), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), + ), + }, + { + Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, tag3), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), + ), + }, + }, + }) +} +func TestAccIBMISInstanceBootVolumeManager_all_update(t *testing.T) { + var vol string + tag1 := "env:prod" + tag2 := "boot:unattached" + tag3 := "delete:false" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVolumeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + ), + }, + { + Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, ""), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), resource.TestCheckResourceAttrSet( @@ -149,6 +307,126 @@ func TestAccIBMISInstanceBootVolumeManager_tag_name_update(t *testing.T) { "ibm_is_instance_boot_volume_manager.boot", "zone"), resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), + ), + }, + { + Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, tag3), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), + ), + }, + }, + }) +} +func TestAccIBMISInstanceBootVolumeManager_name_update(t *testing.T) { + var vol string + name1 := fmt.Sprintf("tfbootvoluat-%d", acctest.RandIntRange(10, 100)) + name2 := fmt.Sprintf("tfbootvoluat-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVolumeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + ), + }, + { + Config: testAccCheckIBMISInstanceBootVolumeManagerNameUpdateConfig(name1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.boot", "name", name1), + ), + }, + { + Config: testAccCheckIBMISInstanceBootVolumeManagerNameUpdateConfig(name2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), resource.TestCheckResourceAttr( "ibm_is_instance_boot_volume_manager.boot", "name", name2), ), @@ -156,42 +434,161 @@ func TestAccIBMISInstanceBootVolumeManager_tag_name_update(t *testing.T) { }, }) } +func TestAccIBMISInstanceBootVolumeManager_accesstag_update(t *testing.T) { + var vol string + tag1 := "access:qa" + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVolumeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + ), + }, + { + Config: testAccCheckIBMISInstanceBootVolumeManagerAccessTagUpdateConfig(tag1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "access_tags.#"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "access_tags.#", "1"), + ), + }, + }, + }) +} func TestAccIBMISInstanceBootVolumeManagerUsertag_basic(t *testing.T) { var vol string - name := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) - tagname := fmt.Sprintf("tfusertag%d", acctest.RandIntRange(10, 100)) - tagnameupdate := fmt.Sprintf("tfusertagupd%d", acctest.RandIntRange(10, 100)) - + tag1 := "env:prod" + tag2 := "boot:unattached" + tag3 := "delete:false" resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, CheckDestroy: testAccCheckIBMISVolumeDestroy, Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccCheckIBMISVolumeUsertagConfig(name, tagname), + { + Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + ), + }, + { + Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, ""), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttr( - "ibm_is_instance_boot_volume_manager.boot", "name", name), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "tags.#"), + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "tags.0"), - resource.TestCheckResourceAttr( - "ibm_is_instance_boot_volume_manager.boot", "tags.0", tagname), + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "2"), ), }, - - resource.TestStep{ - Config: testAccCheckIBMISVolumeUsertagConfig(name, tagnameupdate), + { + Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, tag3), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "tags.#"), + "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "tags.0"), - resource.TestCheckResourceAttr( - "ibm_is_instance_boot_volume_manager.boot", "tags.0", tagnameupdate), + "ibm_is_instance_boot_volume_manager.boot", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "crn"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "health_state"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "id"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "iops"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "name"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "profile"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.boot", "zone"), + resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), ), }, }, @@ -297,15 +694,35 @@ func testAccCheckIBMISInstanceBootVolumeManagerConfig() string { } -func testAccCheckIBMISInstanceBootVolumeManagerNameTagUpdateConfig(name, tag1, tag2, tag3 string) string { +func testAccCheckIBMISInstanceBootVolumeManagerNameUpdateConfig(name string) string { + return fmt.Sprintf( + ` + resource "ibm_is_instance_boot_volume_manager" "boot"{ + volume_id = "%s" + name = "%s" + } +`, acc.VSIUnattachedBootVolumeID, name) + +} + +func testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, tag3 string) string { return fmt.Sprintf( ` resource "ibm_is_instance_boot_volume_manager" "boot"{ volume_id = "%s" - name = "%s" tags = "%s" == "" ? ["%s", "%s"] : ["%s", "%s", "%s"] } -`, acc.VSIUnattachedBootVolumeID, name, tag3, tag1, tag2, tag1, tag2, tag3) +`, acc.VSIUnattachedBootVolumeID, tag3, tag1, tag2, tag1, tag2, tag3) + +} +func testAccCheckIBMISInstanceBootVolumeManagerAccessTagUpdateConfig(tag1 string) string { + return fmt.Sprintf( + ` + resource "ibm_is_instance_boot_volume_manager" "boot"{ + volume_id = "%s" + access_tags = ["%s"] + } +`, acc.VSIUnattachedBootVolumeID, tag1) } diff --git a/website/docs/r/is_instance_boot_volume_manager.html.markdown b/website/docs/r/is_instance_boot_volume_manager.html.markdown index b108f80ec6..ec5d4eca1f 100644 --- a/website/docs/r/is_instance_boot_volume_manager.html.markdown +++ b/website/docs/r/is_instance_boot_volume_manager.html.markdown @@ -59,7 +59,6 @@ Review the argument references that you can specify for your resource. ~> **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. - `iops` - (Optional, Integer) The total input/ output operations per second (IOPS) for your storage. This value is required for `custom` storage profiles only. @@ -85,12 +84,12 @@ 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. -- `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) - `volume_id` - (Required, Forces new resource, String) The volume id of the volume from boot volume. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. +- `bandwidth` - (Integer) The maximum bandwidth (in megabits per second) for the volume - `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). @@ -110,6 +109,7 @@ In addition to all argument reference list, you can access the following attribu - `crn` - (String) The CRN for the volume. - `encryption_key` - (String) The key to use for encrypting this volume. - `resource_group` - (String) The resource group ID for this volume. +- `source_snapshot` - (String) The ID of snapshot from which to clone the volume. - `zone` - (String) The location of the volume. ## Import From 17c60729579f39ed36f4617d51f3c3fad5c28249 Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Fri, 26 May 2023 10:54:45 +0530 Subject: [PATCH 18/21] reordered logic to update --- ...rce_ibm_is_instance_boot_volume_manager.go | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go index 91e298649e..e210feb9d1 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go @@ -455,10 +455,6 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { delete = true } - if d.HasChange(isVolumeName) { - name = d.Get(isVolumeName).(string) - hasNameChanged = true - } var capacity int64 if delete { deleteAllInstanceBootSnapshots(sess, id) @@ -498,26 +494,6 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { } options.IfMatch = &eTag - //name update - volumeNamePatchModel := &vpcv1.VolumePatch{} - if hasNameChanged { - volumeNamePatchModel.Name = &name - volumeNamePatch, err := volumeNamePatchModel.AsPatch() - if err != nil { - return fmt.Errorf("[ERROR] Error calling asPatch for volumeNamePatch in Instance boot volume : %s", err) - } - options.VolumePatch = volumeNamePatch - _, response, err = sess.UpdateVolume(options) - eTag = response.Headers.Get("ETag") - if err != nil { - return err - } - _, err = isWaitForInstanceBootVolumeManagerAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), &eTag) - if err != nil { - return err - } - } - // profile/ iops update if d.HasChange(isVolumeProfileName) || d.HasChange(isVolumeIops) { volumeProfilePatchModel := &vpcv1.VolumePatch{} @@ -678,6 +654,30 @@ func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { } } + //name update + if d.HasChange(isVolumeName) { + name = d.Get(isVolumeName).(string) + hasNameChanged = true + } + volumeNamePatchModel := &vpcv1.VolumePatch{} + if hasNameChanged { + volumeNamePatchModel.Name = &name + volumeNamePatch, err := volumeNamePatchModel.AsPatch() + if err != nil { + return fmt.Errorf("[ERROR] Error calling asPatch for volumeNamePatch in Instance boot volume : %s", err) + } + options.VolumePatch = volumeNamePatch + _, response, err = sess.UpdateVolume(options) + eTag = response.Headers.Get("ETag") + if err != nil { + return err + } + _, err = isWaitForInstanceBootVolumeManagerAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), &eTag) + if err != nil { + return err + } + } + return nil } From 156167645dab01c9a0f1376a62b046e3ed4322eb Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Fri, 26 May 2023 11:48:11 +0530 Subject: [PATCH 19/21] updated tests --- ...bm_is_instance_boot_volume_manager_test.go | 141 ++++++++++-------- 1 file changed, 76 insertions(+), 65 deletions(-) diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go index 63e4af3a70..d3b12ef419 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go @@ -57,9 +57,15 @@ func TestAccIBMISInstanceBootVolumeManager_basic(t *testing.T) { func TestAccIBMISInstanceBootVolumeManager_capacity_update(t *testing.T) { var vol string - tag1 := "env:prod" - tag2 := "boot:unattached" - tag3 := "delete:false" + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + capacity0 := int64(0) + capacity := int64(180) + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, @@ -92,7 +98,7 @@ func TestAccIBMISInstanceBootVolumeManager_capacity_update(t *testing.T) { ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, ""), + Config: testAccCheckIBMISInstanceBootVolumeManagerCapacityUpdateConfig(vpcname, subnetname, sshname, publicKey, name, capacity0), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), resource.TestCheckResourceAttrSet( @@ -116,11 +122,10 @@ func TestAccIBMISInstanceBootVolumeManager_capacity_update(t *testing.T) { resource.TestCheckResourceAttrSet( "ibm_is_instance_boot_volume_manager.boot", "zone"), resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, tag3), + Config: testAccCheckIBMISInstanceBootVolumeManagerCapacityUpdateConfig(vpcname, subnetname, sshname, publicKey, name, capacity), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), resource.TestCheckResourceAttrSet( @@ -144,17 +149,23 @@ func TestAccIBMISInstanceBootVolumeManager_capacity_update(t *testing.T) { resource.TestCheckResourceAttrSet( "ibm_is_instance_boot_volume_manager.boot", "zone"), resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "capacity", fmt.Sprintf("%d", capacity)), ), }, }, }) } -func TestAccIBMISInstanceBootVolumeManager_iops_update(t *testing.T) { +func TestAccIBMISInstanceBootVolumeManager_profile_update(t *testing.T) { var vol string - tag1 := "env:prod" - tag2 := "boot:unattached" - tag3 := "delete:false" + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + profile0 := "" + profile := "10iops-tier" + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, @@ -187,7 +198,7 @@ func TestAccIBMISInstanceBootVolumeManager_iops_update(t *testing.T) { ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, ""), + Config: testAccCheckIBMISInstanceBootVolumeManagerProfileUpdateConfig(vpcname, subnetname, sshname, publicKey, name, profile0), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), resource.TestCheckResourceAttrSet( @@ -211,11 +222,10 @@ func TestAccIBMISInstanceBootVolumeManager_iops_update(t *testing.T) { resource.TestCheckResourceAttrSet( "ibm_is_instance_boot_volume_manager.boot", "zone"), resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, tag3), + Config: testAccCheckIBMISInstanceBootVolumeManagerProfileUpdateConfig(vpcname, subnetname, sshname, publicKey, name, profile), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), resource.TestCheckResourceAttrSet( @@ -239,12 +249,13 @@ func TestAccIBMISInstanceBootVolumeManager_iops_update(t *testing.T) { resource.TestCheckResourceAttrSet( "ibm_is_instance_boot_volume_manager.boot", "zone"), resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "profile", profile), ), }, }, }) } + func TestAccIBMISInstanceBootVolumeManager_all_update(t *testing.T) { var vol string tag1 := "env:prod" @@ -726,7 +737,7 @@ func testAccCheckIBMISInstanceBootVolumeManagerAccessTagUpdateConfig(tag1 string } -func testAccCheckIBMISInstanceBootVolumeManagerTierConfig(vpcname, subnetname, sshname, publicKey, name, volName, profileName string) string { +func testAccCheckIBMISInstanceBootVolumeManagerCapacityUpdateConfig(vpcname, subnetname, sshname, publicKey, name string, capacity int64) string { return fmt.Sprintf( ` resource "ibm_is_vpc" "testacc_vpc" { @@ -744,44 +755,31 @@ func testAccCheckIBMISInstanceBootVolumeManagerTierConfig(vpcname, subnetname, s name = "%s" public_key = "%s" } - resource "ibm_is_volume" "storage"{ - name = "%s" - profile = "%s" - zone = "%s" - } + resource "ibm_is_instance" "testacc_instance" { name = "%s" - image = "%s" profile = "%s" - volumes = [ibm_is_instance_boot_volume_manager.boot.id] + boot_volume { + volume_id = ibm_is_instance_boot_volume_manager.boot.id + auto_delete_volume = false + } primary_network_interface { subnet = ibm_is_subnet.testacc_subnet.id } vpc = ibm_is_vpc.testacc_vpc.id zone = "%s" keys = [ibm_is_ssh_key.testacc_sshkey.id] - } - -`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, volName, profileName, acc.ISZoneName, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) + } + resource "ibm_is_instance_boot_volume_manager" "boot" { + volume_id = "%s" + capacity = %d == 0 ? null : %d + } + `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.InstanceProfileName, acc.ISZoneName, acc.VSIUnattachedBootVolumeID, capacity, capacity) } - -func testAccCheckIBMISInstanceBootVolumeManagerAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, capacityArray string) string { +func testAccCheckIBMISInstanceBootVolumeManagerProfileUpdateConfig(vpcname, subnetname, sshname, publicKey, name, profile string) string { return fmt.Sprintf( ` - variable "vsi_vol_size" { - description = "capacity array" - default = %s - } - - resource "ibm_is_volume" "storage"{ - name = "tf-vol-att-${count.index}" - count = length(var.vsi_vol_size) - profile = "general-purpose" - zone = "%s" - capacity = var.vsi_vol_size[count.index] - } - resource "ibm_is_vpc" "testacc_vpc" { name = "%s" } @@ -794,15 +792,17 @@ func testAccCheckIBMISInstanceBootVolumeManagerAttachmentDeleteConfig(vpcname, s } resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" + name = "%s" + public_key = "%s" } - + resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - volumes = ibm_is_instance_boot_volume_manager.boot[*].id + name = "%s" + profile = "%s" + boot_volume { + volume_id = ibm_is_instance_boot_volume_manager.boot.id + auto_delete_volume = false + } primary_network_interface { subnet = ibm_is_subnet.testacc_subnet.id } @@ -810,13 +810,30 @@ func testAccCheckIBMISInstanceBootVolumeManagerAttachmentDeleteConfig(vpcname, s zone = "%s" keys = [ibm_is_ssh_key.testacc_sshkey.id] } -`, capacityArray, acc.ISZoneName, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, insname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) + resource "ibm_is_instance_boot_volume_manager" "boot" { + volume_id = "%s" + profile = "%s" == "" ? null : "%s" + } + `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.InstanceProfileName, acc.ISZoneName, acc.VSIUnattachedBootVolumeID, profile, profile) } -func testAccCheckIBMISInstanceBootVolumeManagerCapacityConfig(vpcname, subnetname, sshname, publicKey, name, volName string, capacity int64) string { +func testAccCheckIBMISInstanceBootVolumeManagerAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, capacityArray string) string { return fmt.Sprintf( ` + variable "vsi_vol_size" { + description = "capacity array" + default = %s + } + + resource "ibm_is_volume" "storage"{ + name = "tf-vol-att-${count.index}" + count = length(var.vsi_vol_size) + profile = "general-purpose" + zone = "%s" + capacity = var.vsi_vol_size[count.index] + } + resource "ibm_is_vpc" "testacc_vpc" { name = "%s" } @@ -829,29 +846,23 @@ func testAccCheckIBMISInstanceBootVolumeManagerCapacityConfig(vpcname, subnetnam } resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" + name = "%s" + public_key = "%s" } - resource "ibm_is_volume" "storage"{ - name = "%s" - profile = "10iops-tier" - zone = "%s" - capacity = %d - } + resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - volumes = [ibm_is_instance_boot_volume_manager.boot.id] + name = "%s" + image = "%s" + profile = "%s" + volumes = ibm_is_instance_boot_volume_manager.boot[*].id primary_network_interface { subnet = ibm_is_subnet.testacc_subnet.id } vpc = ibm_is_vpc.testacc_vpc.id zone = "%s" keys = [ibm_is_ssh_key.testacc_sshkey.id] - } - -`, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, volName, acc.ISZoneName, capacity, name, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) + } +`, capacityArray, acc.ISZoneName, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, insname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) } From 15864988864198900189994c6e70b9ada1653bb4 Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Fri, 26 May 2023 14:55:38 +0530 Subject: [PATCH 20/21] Update resource_ibm_is_instance_boot_volume_manager_test.go --- ...bm_is_instance_boot_volume_manager_test.go | 67 +++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go index d3b12ef419..eada68f4e0 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go @@ -255,12 +255,22 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE }, }) } - func TestAccIBMISInstanceBootVolumeManager_all_update(t *testing.T) { var vol string + vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) + name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) + volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) + subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + profile := "10iops-tier" + capacity := int64(200) tag1 := "env:prod" tag2 := "boot:unattached" tag3 := "delete:false" + accesstag := "access:qa" + publicKey := strings.TrimSpace(` +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR +`) + sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, @@ -293,7 +303,7 @@ func TestAccIBMISInstanceBootVolumeManager_all_update(t *testing.T) { ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, ""), + Config: testAccCheckIBMISInstanceBootVolumeManagerAllUpdateConfig(vpcname, subnetname, sshname, publicKey, name, "", tag1, tag2, "", "", "", 0), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), resource.TestCheckResourceAttrSet( @@ -317,11 +327,10 @@ func TestAccIBMISInstanceBootVolumeManager_all_update(t *testing.T) { resource.TestCheckResourceAttrSet( "ibm_is_instance_boot_volume_manager.boot", "zone"), resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, tag3), + Config: testAccCheckIBMISInstanceBootVolumeManagerAllUpdateConfig(vpcname, subnetname, sshname, publicKey, name, profile, tag1, tag2, tag3, accesstag, volname, capacity), Check: resource.ComposeTestCheckFunc( testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), resource.TestCheckResourceAttrSet( @@ -346,11 +355,17 @@ func TestAccIBMISInstanceBootVolumeManager_all_update(t *testing.T) { "ibm_is_instance_boot_volume_manager.boot", "zone"), resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "access_tags.#", "1"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "access_tags.#", "1"), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "profile", profile), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "name", volname), + resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "capacity", fmt.Sprintf("%d", capacity)), ), }, }, }) } + func TestAccIBMISInstanceBootVolumeManager_name_update(t *testing.T) { var vol string name1 := fmt.Sprintf("tfbootvoluat-%d", acctest.RandIntRange(10, 100)) @@ -816,6 +831,50 @@ func testAccCheckIBMISInstanceBootVolumeManagerProfileUpdateConfig(vpcname, subn } `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.InstanceProfileName, acc.ISZoneName, acc.VSIUnattachedBootVolumeID, profile, profile) +} +func testAccCheckIBMISInstanceBootVolumeManagerAllUpdateConfig(vpcname, subnetname, sshname, publicKey, name, profile, tag1, tag2, tag3, accesstag, volname string, capacity int64) string { + return fmt.Sprintf( + ` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + + resource "ibm_is_subnet" "testacc_subnet" { + name = "%s" + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + total_ipv4_address_count = 16 + } + + resource "ibm_is_ssh_key" "testacc_sshkey" { + name = "%s" + public_key = "%s" + } + + resource "ibm_is_instance" "testacc_instance" { + name = "%s" + profile = "%s" + boot_volume { + volume_id = ibm_is_instance_boot_volume_manager.boot.id + auto_delete_volume = false + } + primary_network_interface { + subnet = ibm_is_subnet.testacc_subnet.id + } + vpc = ibm_is_vpc.testacc_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.testacc_sshkey.id] + } + resource "ibm_is_instance_boot_volume_manager" "boot" { + volume_id = "%s" + profile = "%s" == "" ? null : "%s" + capacity = %d == 0 ? null : %d + access_tags = "%s" == "" ? null : ["%s"] + tags = "%s" == "" ? null : ["%s", "%s", "%s"] + name = "%s" == "" ? null : "%s" + } + `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.InstanceProfileName, acc.ISZoneName, acc.VSIUnattachedBootVolumeID, profile, profile, capacity, capacity, accesstag, accesstag, tag3, tag1, tag2, tag3, volname, volname) + } func testAccCheckIBMISInstanceBootVolumeManagerAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, capacityArray string) string { From c35f7f35c61c47fea6bea1e0185c25b4ea342be7 Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Thu, 12 Jun 2025 13:18:24 +0530 Subject: [PATCH 21/21] updated as per error toolchain guidelines --- ibm/provider/provider.go | 2 + ...rce_ibm_is_instance_boot_volume_manager.go | 1165 ++++++++++------- ...bm_is_instance_boot_volume_manager_test.go | 1002 +++++--------- ...instance_boot_volume_manager.html.markdown | 232 +++- 4 files changed, 1177 insertions(+), 1224 deletions(-) diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 93e4eb2a65..d9ad3bbde7 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -1300,6 +1300,7 @@ func Provider() *schema.Provider { "ibm_is_floating_ip": vpc.ResourceIBMISFloatingIP(), "ibm_is_flow_log": vpc.ResourceIBMISFlowLog(), "ibm_is_instance": vpc.ResourceIBMISInstance(), + "ibm_is_instance_boot_volume_manager": vpc.ResourceIBMISInstanceBootVolumeManager(), "ibm_is_instance_action": vpc.ResourceIBMISInstanceAction(), "ibm_is_instance_network_attachment": vpc.ResourceIBMIsInstanceNetworkAttachment(), "ibm_is_instance_network_interface": vpc.ResourceIBMIsInstanceNetworkInterface(), @@ -2031,6 +2032,7 @@ func Validator() validate.ValidatorDict { "ibm_is_image_export_job": vpc.ResourceIBMIsImageExportValidator(), "ibm_is_instance_template": vpc.ResourceIBMISInstanceTemplateValidator(), "ibm_is_instance": vpc.ResourceIBMISInstanceValidator(), + "ibm_is_instance_boot_volume_manager": vpc.ResourceIBMISInstanceBootVolumeManagerValidator(), "ibm_is_instance_action": vpc.ResourceIBMISInstanceActionValidator(), "ibm_is_instance_network_attachment": vpc.ResourceIBMIsInstanceNetworkAttachmentValidator(), "ibm_is_instance_network_interface": vpc.ResourceIBMIsInstanceNetworkInterfaceValidator(), diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go index e210feb9d1..2fb88d11e7 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Copyright IBM Corp. 2017, 2025 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package vpc @@ -13,27 +13,34 @@ import ( "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/go-sdk-core/v5/core" "github.com/IBM/vpc-go-sdk/vpcv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) const ( - isInstanceBootVolumeManagerDelete = "delete" + isInstanceBootVolumeIdentifier = "boot_volume" + isInstanceBootVolumeManagerDelete = "delete_volume" ) func ResourceIBMISInstanceBootVolumeManager() *schema.Resource { return &schema.Resource{ - Create: resourceIBMISInstanceBootVolumeManagerCreate, - Read: resourceIBMISInstanceBootVolumeManagerRead, - Update: resourceIBMISInstanceBootVolumeManagerUpdate, - Delete: resourceIBMISInstanceBootVolumeManagerDelete, - Exists: resourceIBMISInstanceBootVolumeManagerExists, - Importer: &schema.ResourceImporter{}, + CreateContext: resourceIBMISInstanceBootVolumeManagerCreate, + ReadContext: resourceIBMISInstanceBootVolumeManagerRead, + UpdateContext: resourceIBMISInstanceBootVolumeManagerUpdate, + DeleteContext: resourceIBMISInstanceBootVolumeManagerDelete, + Exists: resourceIBMISInstanceBootVolumeManagerExists, + Importer: &schema.ResourceImporter{ + StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + return []*schema.ResourceData{d}, nil + }, + }, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), Delete: schema.DefaultTimeout(10 * time.Minute), }, @@ -43,10 +50,6 @@ func ResourceIBMISInstanceBootVolumeManager() *schema.Resource { return flex.ResourceTagsCustomizeDiff(diff) }, ), - customdiff.Sequence( - func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { - return flex.ResourceVolumeValidate(diff) - }), customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { return flex.ResourceValidateAccessTags(diff, v) @@ -54,92 +57,157 @@ func ResourceIBMISInstanceBootVolumeManager() *schema.Resource { ), Schema: map[string]*schema.Schema{ - - isInstanceBootVolumeId: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", isVolumeName), - Description: "Volume name", + isInstanceBootVolumeIdentifier: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The unique identifier for the boot volume", }, isVolumeName: { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", isVolumeName), - Description: "Volume name", + Description: "The user-defined name for this boot volume", }, - isVolumeProfileName: { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", isVolumeProfileName), - Description: "Volume profile name", + Description: "The globally unique name of the volume profile to use for this volume", + }, + isVolumeCapacity: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", isVolumeCapacity), + Description: "The capacity of the volume in gigabytes", + }, + isVolumeIops: { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", isVolumeIops), + Description: "The maximum I/O operations per second (IOPS) for the volume", + }, + isInstanceBootVolumeManagerDelete: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "If set to true, the boot volume will be deleted when this resource is destroyed", + }, + isVolumeTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", "tags")}, + Set: flex.ResourceIBMVPCHash, + Description: "User tags for the boot volume", + }, + isVolumeAccessTags: { + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", "accesstag")}, + Set: flex.ResourceIBMVPCHash, + Description: "Access management tags for the boot volume", + }, + isVolumeDeleteAllSnapshots: { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "If set to true, all snapshots created from this volume will be deleted when the volume is deleted", }, + // Computed attributes isVolumeZone: { Type: schema.TypeString, Computed: true, - Description: "Zone name", + Description: "The zone where this volume resides", }, - isVolumeEncryptionKey: { Type: schema.TypeString, Computed: true, - Description: "Volume encryption key info", + Description: "The CRN of the encryption key used to encrypt this volume", }, - - isInstanceBootVolumeManagerDelete: { - Type: schema.TypeBool, - Optional: true, - Description: "Volume encryption key info", - }, - isVolumeEncryptionType: { Type: schema.TypeString, Computed: true, - Description: "Volume encryption type info", - }, - - isVolumeCapacity: { - Type: schema.TypeInt, - Optional: true, - Computed: true, - ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", isVolumeCapacity), - Description: "Volume capacity value", + Description: "The type of encryption used on the volume", }, isVolumeSourceSnapshot: { Type: schema.TypeString, Computed: true, - Description: "The unique identifier for this snapshot", + Description: "The unique identifier for the snapshot from which this volume was created", }, isVolumeResourceGroup: { - Type: schema.TypeString, + Type: schema.TypeList, Computed: true, - Description: "Resource group name", - }, - isVolumeIops: { - Type: schema.TypeInt, - Optional: true, - Computed: true, - ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", isVolumeIops), - Description: "IOPS value for the Volume", + Description: "The resource group for this volume", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this resource group", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this resource group", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this resource group", + }, + }, + }, }, isVolumeCrn: { Type: schema.TypeString, Computed: true, - Description: "CRN value for the volume instance", + Description: "The CRN of the volume", }, isVolumeStatus: { Type: schema.TypeString, Computed: true, - Description: "Volume status", + Description: "The status of the volume", + }, + isVolumeHealthState: { + Type: schema.TypeString, + Computed: true, + Description: "The health state of this volume", + }, + isVolumeHealthReasons: { + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current health_state (if any)", + 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", + }, + }, + }, }, - isVolumeStatusReasons: { - Type: schema.TypeList, - Computed: true, + Type: schema.TypeList, + Computed: true, + Description: "The reasons for the current status (if any)", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ isVolumeStatusReasonsCode: { @@ -147,13 +215,11 @@ func ResourceIBMISInstanceBootVolumeManager() *schema.Resource { Computed: true, Description: "A snake case string succinctly identifying the status reason", }, - isVolumeStatusReasonsMessage: { Type: schema.TypeString, Computed: true, Description: "An explanation of the status reason", }, - isVolumeStatusReasonsMoreInfo: { Type: schema.TypeString, Computed: true, @@ -162,113 +228,132 @@ func ResourceIBMISInstanceBootVolumeManager() *schema.Resource { }, }, }, - isVolumeHealthReasons: { - Type: schema.TypeList, - Computed: true, + isVolumeBandwidth: { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum bandwidth (in megabits per second) for the volume", + }, + "volume_attachments": { + Type: schema.TypeList, + Computed: true, + Description: "The volume attachments for this volume", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - isVolumeHealthReasonsCode: { + "delete_volume_on_instance_delete": { + Type: schema.TypeBool, + Computed: true, + Description: "If set to true, this volume will be deleted when the instance is deleted", + }, + "device": { + Type: schema.TypeList, + Computed: true, + Description: "A unique identifier for the device which is exposed to the instance operating system", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "A unique identifier for the device which is exposed to the instance operating system", + }, + }, + }, + }, + "href": { Type: schema.TypeString, Computed: true, - Description: "A snake case string succinctly identifying the reason for this health state.", + Description: "The URL for this volume attachment", }, - - isVolumeHealthReasonsMessage: { + "id": { Type: schema.TypeString, Computed: true, - Description: "An explanation of the reason for this health state.", + Description: "The unique identifier for this volume attachment", }, - - isVolumeHealthReasonsMoreInfo: { + "instance": { + Type: schema.TypeList, + Computed: true, + Description: "The attached instance", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "crn": { + Type: schema.TypeString, + Computed: true, + Description: "The CRN for this virtual server instance", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URL for this virtual server instance", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The unique identifier for this virtual server instance", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The user-defined name for this virtual server instance", + }, + }, + }, + }, + "name": { Type: schema.TypeString, Computed: true, - Description: "Link to documentation about the reason for this health state.", + Description: "The user-defined name for this volume attachment", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of volume attachment", }, }, }, }, - - isVolumeHealthState: { - Type: schema.TypeString, - Computed: true, - Description: "The health of this resource.", - }, - isVolumeDeleteAllSnapshots: { - Type: schema.TypeBool, - Optional: true, - Description: "Deletes all snapshots created from this volume", - }, - isVolumeTags: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", "tags")}, - Set: flex.ResourceIBMVPCHash, - Description: "UserTags for the volume instance", - }, - isVolumeAccessTags: { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString, ValidateFunc: validate.InvokeValidator("ibm_is_instance_boot_volume_manager", "accesstag")}, - Set: flex.ResourceIBMVPCHash, - Description: "Access management tags for the volume instance", - }, - flex.ResourceControllerURL: { Type: schema.TypeString, Computed: true, Description: "The URL of the IBM Cloud dashboard that can be used to explore and view details about this instance", }, - flex.ResourceName: { Type: schema.TypeString, Computed: true, Description: "The name of the resource", }, - flex.ResourceCRN: { Type: schema.TypeString, Computed: true, - Description: "The crn of the resource", + Description: "The CRN of the resource", }, - flex.ResourceStatus: { Type: schema.TypeString, Computed: true, Description: "The status of the resource", }, - flex.ResourceGroupName: { Type: schema.TypeString, Computed: true, Description: "The resource group name in which resource is provisioned", }, - - isVolumeBandwidth: { - Type: schema.TypeInt, - Computed: true, - Description: "The maximum bandwidth (in megabits per second) for the volume", - }, }, } } func ResourceIBMISInstanceBootVolumeManagerValidator() *validate.ResourceValidator { - validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, validate.ValidateSchema{ Identifier: isVolumeName, ValidateFunctionIdentifier: validate.ValidateRegexpLen, Type: validate.TypeString, - Required: true, + Optional: true, Regexp: `^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$`, MinValueLength: 1, MaxValueLength: 63}) validateSchema = append(validateSchema, validate.ValidateSchema{ - Identifier: isInstanceBootVolumeId, + Identifier: isInstanceBootVolumeIdentifier, ValidateFunctionIdentifier: validate.ValidateNoZeroValues, Type: validate.TypeString}) validateSchema = append(validateSchema, @@ -294,7 +379,7 @@ func ResourceIBMISInstanceBootVolumeManagerValidator() *validate.ResourceValidat ValidateFunctionIdentifier: validate.IntBetween, Type: validate.TypeInt, MinValue: "10", - MaxValue: "250"}) + MaxValue: "16000"}) validateSchema = append(validateSchema, validate.ValidateSchema{ Identifier: isVolumeIops, @@ -312,497 +397,639 @@ func ResourceIBMISInstanceBootVolumeManagerValidator() *validate.ResourceValidat MinValueLength: 1, MaxValueLength: 128}) - ibmISVolumeResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_boot_volume_manager", Schema: validateSchema} - return &ibmISVolumeResourceValidator + ibmISInstanceBootVolumeManagerResourceValidator := validate.ResourceValidator{ResourceName: "ibm_is_instance_boot_volume_manager", Schema: validateSchema} + return &ibmISInstanceBootVolumeManagerResourceValidator } -func resourceIBMISInstanceBootVolumeManagerCreate(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISInstanceBootVolumeManagerCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + sess, err := vpcClient(meta) + if err != nil { + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "create", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + bootVolumeID := d.Get(isInstanceBootVolumeIdentifier).(string) - volId := d.Get(isInstanceBootVolumeId).(string) - d.SetId(volId) - err := resourceIBMISInstanceBootVolumeManagerRead(d, meta) + // Verify the boot volume exists + getVolumeOptions := &vpcv1.GetVolumeOptions{ + ID: &bootVolumeID, + } + volume, _, err := sess.GetVolumeWithContext(context, getVolumeOptions) if err != nil { - return err + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetVolumeWithContext failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - return resourceIBMISInstanceBootVolumeManagerUpdate(d, meta) -} + d.SetId(bootVolumeID) -func resourceIBMISInstanceBootVolumeManagerRead(d *schema.ResourceData, meta interface{}) error { + // Handle tags on creation + v := os.Getenv("IC_ENV_TAGS") + if _, ok := d.GetOk(isVolumeTags); ok || v != "" { + _, newList := d.GetChange(isVolumeTags) + userTagsArray := make([]string, 0) + if newList != nil { + for _, tag := range newList.(*schema.Set).List() { + userTagsArray = append(userTagsArray, tag.(string)) + } + } + if v != "" { + envTags := strings.Split(v, ",") + userTagsArray = append(userTagsArray, envTags...) + } + if len(userTagsArray) > 0 { + volumePatchModel := &vpcv1.VolumePatch{ + UserTags: userTagsArray, + } + volumePatch, err := volumePatchModel.AsPatch() + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("volumePatchModel.AsPatch() failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + updateVolumeOptions := &vpcv1.UpdateVolumeOptions{ + ID: &bootVolumeID, + VolumePatch: volumePatch, + } + _, _, err = sess.UpdateVolumeWithContext(context, updateVolumeOptions) + if err != nil { + log.Printf("Error on create of boot volume manager (%s) tags: %s", d.Id(), err) + } + } + } - id := d.Id() - err := instancebootvolGet(d, meta, id) - if err != nil { - return err + if _, ok := d.GetOk(isVolumeAccessTags); ok { + oldList, newList := d.GetChange(isVolumeAccessTags) + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *volume.CRN, "", isVolumeAccessTagType) + if err != nil { + log.Printf("Error on create of boot volume manager (%s) access tags: %s", d.Id(), err) + } } - return nil + + return resourceIBMISInstanceBootVolumeManagerUpdate(context, d, meta) } -func instancebootvolGet(d *schema.ResourceData, meta interface{}, id string) error { +func resourceIBMISInstanceBootVolumeManagerRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { - return err + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - options := &vpcv1.GetVolumeOptions{ + + id := d.Id() + getVolumeOptions := &vpcv1.GetVolumeOptions{ ID: &id, } - vol, response, err := sess.GetVolume(options) + volume, response, err := sess.GetVolumeWithContext(context, getVolumeOptions) if err != nil { if response != nil && response.StatusCode == 404 { d.SetId("") return nil } - return fmt.Errorf("[ERROR] Error getting Instance boot volume (%s): %s\n%s", id, err, response) + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetVolumeWithContext failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - d.SetId(*vol.ID) - d.Set(isVolumeName, *vol.Name) - d.Set(isVolumeProfileName, *vol.Profile.Name) - d.Set(isVolumeZone, *vol.Zone.Name) - if vol.EncryptionKey != nil { - d.Set(isVolumeEncryptionKey, vol.EncryptionKey.CRN) + + if err = d.Set(isInstanceBootVolumeId, id); err != nil { + err = fmt.Errorf("Error setting boot_volume: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-boot_volume").GetDiag() } - if vol.Encryption != nil { - d.Set(isVolumeEncryptionType, vol.Encryption) + + if !core.IsNil(volume.Name) { + if err = d.Set(isVolumeName, *volume.Name); err != nil { + err = fmt.Errorf("Error setting name: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-name").GetDiag() + } } - d.Set(isVolumeIops, *vol.Iops) - d.Set(isVolumeCapacity, *vol.Capacity) - d.Set(isVolumeCrn, *vol.CRN) - if vol.SourceSnapshot != nil { - d.Set(isVolumeSourceSnapshot, *vol.SourceSnapshot.ID) + + if !core.IsNil(volume.Profile) { + if err = d.Set(isVolumeProfileName, *volume.Profile.Name); err != nil { + err = fmt.Errorf("Error setting profile: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-profile").GetDiag() + } + } + + if !core.IsNil(volume.Zone) { + if err = d.Set(isVolumeZone, *volume.Zone.Name); err != nil { + err = fmt.Errorf("Error setting zone: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-zone").GetDiag() + } + } + + if volume.EncryptionKey != nil { + if err = d.Set(isVolumeEncryptionKey, volume.EncryptionKey.CRN); err != nil { + err = fmt.Errorf("Error setting encryption_key: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-encryption_key").GetDiag() + } + } + + if volume.Encryption != nil { + if err = d.Set(isVolumeEncryptionType, *volume.Encryption); err != nil { + err = fmt.Errorf("Error setting encryption_type: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-encryption_type").GetDiag() + } } - d.Set(isVolumeStatus, *vol.Status) - if vol.HealthState != nil { - d.Set(isVolumeHealthState, *vol.HealthState) + + if !core.IsNil(volume.Capacity) { + if err = d.Set(isVolumeCapacity, flex.IntValue(volume.Capacity)); err != nil { + err = fmt.Errorf("Error setting capacity: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-capacity").GetDiag() + } } - d.Set(isVolumeBandwidth, int(*vol.Bandwidth)) - //set the status reasons - if vol.StatusReasons != nil { + + if !core.IsNil(volume.Iops) { + if err = d.Set(isVolumeIops, flex.IntValue(volume.Iops)); err != nil { + err = fmt.Errorf("Error setting iops: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-iops").GetDiag() + } + } + + if !core.IsNil(volume.CRN) { + if err = d.Set(isVolumeCrn, *volume.CRN); err != nil { + err = fmt.Errorf("Error setting crn: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-crn").GetDiag() + } + } + + if volume.SourceSnapshot != nil { + if err = d.Set(isVolumeSourceSnapshot, *volume.SourceSnapshot.ID); err != nil { + err = fmt.Errorf("Error setting source_snapshot: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-source_snapshot").GetDiag() + } + } + + if !core.IsNil(volume.Status) { + if err = d.Set(isVolumeStatus, *volume.Status); err != nil { + err = fmt.Errorf("Error setting status: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-status").GetDiag() + } + } + + if volume.HealthState != nil { + if err = d.Set(isVolumeHealthState, *volume.HealthState); err != nil { + err = fmt.Errorf("Error setting health_state: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-health_state").GetDiag() + } + } + + if !core.IsNil(volume.Bandwidth) { + if err = d.Set(isVolumeBandwidth, flex.IntValue(volume.Bandwidth)); err != nil { + err = fmt.Errorf("Error setting bandwidth: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-bandwidth").GetDiag() + } + } + + // Handle resource group + resourceGroupList := []map[string]interface{}{} + if volume.ResourceGroup != nil { + resourceGroupMap := map[string]interface{}{ + "href": *volume.ResourceGroup.Href, + "id": *volume.ResourceGroup.ID, + "name": *volume.ResourceGroup.Name, + } + resourceGroupList = append(resourceGroupList, resourceGroupMap) + if err = d.Set(flex.ResourceGroupName, *volume.ResourceGroup.Name); err != nil { + err = fmt.Errorf("Error setting resource_group_name: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-resource_group_name").GetDiag() + } + } + if err = d.Set(isVolumeResourceGroup, resourceGroupList); err != nil { + err = fmt.Errorf("Error setting resource_group: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-resource_group").GetDiag() + } + + // Handle status reasons + if volume.StatusReasons != nil { statusReasonsList := make([]map[string]interface{}, 0) - for _, sr := range vol.StatusReasons { + for _, sr := range volume.StatusReasons { currentSR := map[string]interface{}{} if sr.Code != nil && sr.Message != nil { currentSR[isVolumeStatusReasonsCode] = *sr.Code currentSR[isVolumeStatusReasonsMessage] = *sr.Message if sr.MoreInfo != nil { - currentSR[isVolumeStatusReasonsMoreInfo] = *sr.Message + currentSR[isVolumeStatusReasonsMoreInfo] = *sr.MoreInfo } statusReasonsList = append(statusReasonsList, currentSR) } } - d.Set(isVolumeStatusReasons, statusReasonsList) - } - if vol.UserTags != nil { - if err = d.Set(isVolumeTags, vol.UserTags); err != nil { - return fmt.Errorf("Error setting user tags: %s", err) + if err = d.Set(isVolumeStatusReasons, statusReasonsList); err != nil { + err = fmt.Errorf("Error setting status_reasons: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-status_reasons").GetDiag() } } - accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *vol.CRN, "", isVolumeAccessTagType) - if err != nil { - log.Printf( - "Error on get of resource volume (%s) access tags: %s", d.Id(), err) - } - d.Set(isVolumeAccessTags, accesstags) - if vol.HealthReasons != nil { + + // Handle health reasons + if volume.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 + for _, hr := range volume.HealthReasons { + currentHR := map[string]interface{}{} + if hr.Code != nil && hr.Message != nil { + currentHR[isVolumeHealthReasonsCode] = *hr.Code + currentHR[isVolumeHealthReasonsMessage] = *hr.Message + if hr.MoreInfo != nil { + currentHR[isVolumeHealthReasonsMoreInfo] = *hr.MoreInfo } - healthReasonsList = append(healthReasonsList, currentSR) + healthReasonsList = append(healthReasonsList, currentHR) } } - d.Set(isVolumeHealthReasons, healthReasonsList) + if err = d.Set(isVolumeHealthReasons, healthReasonsList); err != nil { + err = fmt.Errorf("Error setting health_reasons: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-health_reasons").GetDiag() + } } - controller, err := flex.GetBaseController(meta) + + // Handle volume attachments + if volume.VolumeAttachments != nil { + volumeAttachmentsList := make([]map[string]interface{}, 0) + for _, va := range volume.VolumeAttachments { + volumeAttachmentMap := map[string]interface{}{} + if va.DeleteVolumeOnInstanceDelete != nil { + volumeAttachmentMap["delete_volume_on_instance_delete"] = *va.DeleteVolumeOnInstanceDelete + } + if va.Device != nil { + deviceList := []map[string]interface{}{} + deviceMap := map[string]interface{}{ + "id": *va.Device.ID, + } + deviceList = append(deviceList, deviceMap) + volumeAttachmentMap["device"] = deviceList + } + if va.Href != nil { + volumeAttachmentMap["href"] = *va.Href + } + if va.ID != nil { + volumeAttachmentMap["id"] = *va.ID + } + if va.Instance != nil { + instanceList := []map[string]interface{}{} + instanceMap := map[string]interface{}{} + if va.Instance.CRN != nil { + instanceMap["crn"] = *va.Instance.CRN + } + if va.Instance.Href != nil { + instanceMap["href"] = *va.Instance.Href + } + if va.Instance.ID != nil { + instanceMap["id"] = *va.Instance.ID + } + if va.Instance.Name != nil { + instanceMap["name"] = *va.Instance.Name + } + instanceList = append(instanceList, instanceMap) + volumeAttachmentMap["instance"] = instanceList + } + if va.Name != nil { + volumeAttachmentMap["name"] = *va.Name + } + if va.Type != nil { + volumeAttachmentMap["type"] = *va.Type + } + volumeAttachmentsList = append(volumeAttachmentsList, volumeAttachmentMap) + } + if err = d.Set("volume_attachments", volumeAttachmentsList); err != nil { + err = fmt.Errorf("Error setting volume_attachments: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-volume_attachments").GetDiag() + } + } + + // Handle tags + if volume.UserTags != nil { + if err = d.Set(isVolumeTags, volume.UserTags); err != nil { + err = fmt.Errorf("Error setting tags: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-tags").GetDiag() + } + } + + accesstags, err := flex.GetGlobalTagsUsingCRN(meta, *volume.CRN, "", isVolumeAccessTagType) if err != nil { - return err + log.Printf("Error on get of boot volume manager (%s) access tags: %s", d.Id(), err) } - d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/storage/storageVolumes") - d.Set(flex.ResourceName, *vol.Name) - d.Set(flex.ResourceCRN, *vol.CRN) - d.Set(flex.ResourceStatus, *vol.Status) - if vol.ResourceGroup != nil { - d.Set(flex.ResourceGroupName, vol.ResourceGroup.Name) - d.Set(isVolumeResourceGroup, *vol.ResourceGroup.ID) + if err = d.Set(isVolumeAccessTags, accesstags); err != nil { + err = fmt.Errorf("Error setting access_tags: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-access_tags").GetDiag() } - return nil -} -func resourceIBMISInstanceBootVolumeManagerUpdate(d *schema.ResourceData, meta interface{}) error { - err := instancebootvolUpdate(d, meta) + controller, err := flex.GetBaseController(meta) if err != nil { - return err + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetBaseController failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + if err = d.Set(flex.ResourceControllerURL, controller+"/vpc-ext/storage/storageVolumes"); err != nil { + err = fmt.Errorf("Error setting resource_controller_url: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-resource_controller_url").GetDiag() + } + if err = d.Set(flex.ResourceName, *volume.Name); err != nil { + err = fmt.Errorf("Error setting resource_name: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-resource_name").GetDiag() } - return resourceIBMISInstanceBootVolumeManagerRead(d, meta) + if err = d.Set(flex.ResourceCRN, *volume.CRN); err != nil { + err = fmt.Errorf("Error setting resource_crn: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-resource_crn").GetDiag() + } + if err = d.Set(flex.ResourceStatus, *volume.Status); err != nil { + err = fmt.Errorf("Error setting resource_status: %s", err) + return flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "read", "set-resource_status").GetDiag() + } + + return nil } -func instancebootvolUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceIBMISInstanceBootVolumeManagerUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { - return err + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "update", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } id := d.Id() - name := "" - hasNameChanged := false - delete := false - - if delete_all_snapshots, ok := d.GetOk(isVolumeDeleteAllSnapshots); ok && delete_all_snapshots.(bool) { - delete = true - } + hasChanged := false - var capacity int64 - if delete { - deleteAllInstanceBootSnapshots(sess, id) - } - - if d.HasChange(isVolumeAccessTags) { - options := &vpcv1.GetVolumeOptions{ + // Handle volume property updates with instance state management + if d.HasChange(isVolumeProfileName) || d.HasChange(isVolumeIops) || d.HasChange(isVolumeCapacity) { + // Get volume details to check attachments + getVolumeOptions := &vpcv1.GetVolumeOptions{ ID: &id, } - vol, response, err := sess.GetVolume(options) + volume, response, err := sess.GetVolumeWithContext(context, getVolumeOptions) if err != nil { - return fmt.Errorf("[ERROR]Error getting Instance boot volume : %s\n%s", err, response) + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetVolumeWithContext failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - oldList, newList := d.GetChange(isVolumeAccessTags) - err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *vol.CRN, "", isVolumeAccessTagType) - if err != nil { - log.Printf( - "Error on update of resource Instance boot volume (%s) access tags: %s", id, err) - } - } + // Check if volume is attached to an instance + if volume.VolumeAttachments != nil && len(volume.VolumeAttachments) > 0 { + instanceID := *volume.VolumeAttachments[0].Instance.ID - optionsget := &vpcv1.GetVolumeOptions{ - ID: &id, - } - _, response, err := sess.GetVolume(optionsget) - if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("[ERROR] Error getting Instance boot volume (%s): %s\n%s", id, err, response) - } - eTag := response.Headers.Get("ETag") - options := &vpcv1.UpdateVolumeOptions{ - ID: &id, - } - options.IfMatch = &eTag - - // profile/ iops update - if d.HasChange(isVolumeProfileName) || d.HasChange(isVolumeIops) { - volumeProfilePatchModel := &vpcv1.VolumePatch{} - volId := d.Id() - getvoloptions := &vpcv1.GetVolumeOptions{ - ID: &volId, - } - vol, response, err := sess.GetVolume(getvoloptions) - if err != nil || vol == nil { - return fmt.Errorf("[ERROR] Error retrieving Instance boot volume (%s) details: %s\n%s", volId, err, response) - } - if vol.VolumeAttachments == nil || len(vol.VolumeAttachments) < 1 { - return fmt.Errorf("[ERROR] Error updating Instance boot volume profile/iops because the specified volume %s is not attached to a virtual server instance ", volId) - } - volAtt := &vol.VolumeAttachments[0] - insId := *volAtt.Instance.ID - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: &insId, - } - instance, response, err := sess.GetInstance(getinsOptions) - if err != nil || instance == nil { - return fmt.Errorf("[ERROR] Error retrieving Instance (%s) to which the boot volume (%s) is attached : %s\n%s", insId, volId, err, response) - } - if instance != nil && *instance.Status != "running" { - actiontype := "start" - createinsactoptions := &vpcv1.CreateInstanceActionOptions{ - InstanceID: &insId, - Type: &actiontype, + // Get instance status + getInstanceOptions := &vpcv1.GetInstanceOptions{ + ID: &instanceID, } - _, response, err = sess.CreateInstanceAction(createinsactoptions) + instance, _, err := sess.GetInstanceWithContext(context, getInstanceOptions) if err != nil { - return fmt.Errorf("[ERROR] Error starting Instance (%s) to which the boot volume (%s) is attached : %s\n%s", insId, volId, err, response) + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetInstanceWithContext failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - _, err = isWaitForInstanceAvailable(sess, insId, d.Timeout(schema.TimeoutCreate), d) - if err != nil { - return err + + // Ensure instance is running for volume updates + if instance != nil && *instance.Status != "running" { + actionType := "start" + createInstanceActionOptions := &vpcv1.CreateInstanceActionOptions{ + InstanceID: &instanceID, + Type: &actionType, + } + _, _, err = sess.CreateInstanceActionWithContext(context, createInstanceActionOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("CreateInstanceActionWithContext failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + _, err = isWaitForInstanceAvailable(sess, instanceID, d.Timeout(schema.TimeoutUpdate), d) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("isWaitForInstanceAvailable failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } } } + + // Get fresh ETag for the update + getVolumeOptions = &vpcv1.GetVolumeOptions{ + ID: &id, + } + _, response, err = sess.GetVolumeWithContext(context, getVolumeOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetVolumeWithContext failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + eTag := response.Headers.Get("ETag") + + volumePatchModel := &vpcv1.VolumePatch{} + if d.HasChange(isVolumeProfileName) { profile := d.Get(isVolumeProfileName).(string) - volumeProfilePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ - Name: &profile, - } - } else if d.HasChange(isVolumeIops) { - profile := d.Get(isVolumeProfileName).(string) - volumeProfilePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ + volumePatchModel.Profile = &vpcv1.VolumeProfileIdentity{ Name: &profile, } + } + + if d.HasChange(isVolumeIops) { iops := int64(d.Get(isVolumeIops).(int)) - volumeProfilePatchModel.Iops = &iops + volumePatchModel.Iops = &iops } - volumeProfilePatch, err := volumeProfilePatchModel.AsPatch() - if err != nil { - return fmt.Errorf("[ERROR] Error calling asPatch for VolumeProfilePatch in Instance boot volume : %s", err) + if d.HasChange(isVolumeCapacity) { + capacity := int64(d.Get(isVolumeCapacity).(int)) + volumePatchModel.Capacity = &capacity } - options.VolumePatch = volumeProfilePatch - _, response, err = sess.UpdateVolume(options) - _, err = isWaitForInstanceBootVolumeManagerAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), &eTag) + + volumePatch, err := volumePatchModel.AsPatch() if err != nil { - return err + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("volumePatchModel.AsPatch() failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - } - // capacity update - if d.HasChange(isVolumeCapacity) { - id := d.Id() - getvolumeoptions := &vpcv1.GetVolumeOptions{ - ID: &id, + updateVolumeOptions := &vpcv1.UpdateVolumeOptions{ + ID: &id, + VolumePatch: volumePatch, + IfMatch: &eTag, } - vol, response, err := sess.GetVolume(getvolumeoptions) + + _, _, err = sess.UpdateVolumeWithContext(context, updateVolumeOptions) if err != nil { - if response != nil && response.StatusCode == 404 { - d.SetId("") - return nil - } - return fmt.Errorf("[ERROR] Error Getting Instance boot volume (%s): %s\n%s", id, err, response) - } - if vol.VolumeAttachments == nil || len(vol.VolumeAttachments) == 0 || *vol.VolumeAttachments[0].ID == "" { - return fmt.Errorf("[ERROR] Error volume capacity can't be updated since Instance boot volume %s is not attached to any instance for VolumePatch", id) - } - insId := vol.VolumeAttachments[0].Instance.ID - getinsOptions := &vpcv1.GetInstanceOptions{ - ID: insId, - } - instance, response, err := sess.GetInstance(getinsOptions) - if err != nil || instance == nil { - return fmt.Errorf("[ERROR] Error retrieving Instance (%s) : %s\n%s", *insId, err, response) + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateVolumeWithContext failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - if instance != nil && *instance.Status != "running" { - actiontype := "start" - createinsactoptions := &vpcv1.CreateInstanceActionOptions{ - InstanceID: insId, - Type: &actiontype, - } - _, response, err = sess.CreateInstanceAction(createinsactoptions) - if err != nil { - return fmt.Errorf("[ERROR] Error starting Instance (%s) : %s\n%s", *insId, err, response) - } - _, err = isWaitForInstanceAvailable(sess, *insId, d.Timeout(schema.TimeoutCreate), d) - if err != nil { - return err - } - } - capacity = int64(d.Get(isVolumeCapacity).(int)) - volumeCapacityPatchModel := &vpcv1.VolumePatch{} - volumeCapacityPatchModel.Capacity = &capacity - volumeCapacityPatch, err := volumeCapacityPatchModel.AsPatch() + _, err = isWaitForVolumeAvailable(sess, id, d.Timeout(schema.TimeoutUpdate)) if err != nil { - return fmt.Errorf("[ERROR] Error calling asPatch for volumeCapacityPatch in Instance boot volume : %s", err) + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("isWaitForVolumeAvailable failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - options.VolumePatch = volumeCapacityPatch - _, response, err = sess.UpdateVolume(options) + hasChanged = true + } + + // Handle name update + if d.HasChange(isVolumeName) { + name := d.Get(isVolumeName).(string) + volumePatchModel := &vpcv1.VolumePatch{ + Name: &name, + } + volumePatch, err := volumePatchModel.AsPatch() if err != nil { - return fmt.Errorf("[ERROR] Error updating Instance boot volume: %s\n%s", err, response) + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("volumePatchModel.AsPatch() failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - _, err = isWaitForInstanceBootVolumeManagerAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), &eTag) + + updateVolumeOptions := &vpcv1.UpdateVolumeOptions{ + ID: &id, + VolumePatch: volumePatch, + } + + _, _, err = sess.UpdateVolumeWithContext(context, updateVolumeOptions) if err != nil { - return err + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateVolumeWithContext failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } + hasChanged = true } - // user tags update + // Handle tags update if d.HasChange(isVolumeTags) { - var userTags *schema.Set - if v, ok := d.GetOk(isVolumeTags); ok { - userTags = v.(*schema.Set) - if userTags != nil && userTags.Len() != 0 { - userTagsArray := make([]string, userTags.Len()) - for i, userTag := range userTags.List() { - userTagStr := userTag.(string) - userTagsArray[i] = userTagStr - } - schematicTags := os.Getenv("IC_ENV_TAGS") - var envTags []string - if schematicTags != "" { - envTags = strings.Split(schematicTags, ",") - userTagsArray = append(userTagsArray, envTags...) - } - volumeNamePatchModel := &vpcv1.VolumePatch{} - volumeNamePatchModel.UserTags = userTagsArray - volumeNamePatch, err := volumeNamePatchModel.AsPatch() - if err != nil { - return fmt.Errorf("[ERROR] Error calling asPatch for volumeNamePatch in Instance boot volume: %s", err) - } - options.IfMatch = &eTag - options.VolumePatch = volumeNamePatch - _, response, err := sess.UpdateVolume(options) - if err != nil { - return fmt.Errorf("[ERROR] Error updating Instance boot volume : %s\n%s", err, response) - } - _, err = isWaitForInstanceBootVolumeManagerAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), &eTag) - if err != nil { - return err - } + userTagsSet := d.Get(isVolumeTags).(*schema.Set) + userTagsArray := make([]string, 0) + if userTagsSet != nil && userTagsSet.Len() > 0 { + for _, userTag := range userTagsSet.List() { + userTagsArray = append(userTagsArray, userTag.(string)) } } - } - //name update - if d.HasChange(isVolumeName) { - name = d.Get(isVolumeName).(string) - hasNameChanged = true - } - volumeNamePatchModel := &vpcv1.VolumePatch{} - if hasNameChanged { - volumeNamePatchModel.Name = &name - volumeNamePatch, err := volumeNamePatchModel.AsPatch() - if err != nil { - return fmt.Errorf("[ERROR] Error calling asPatch for volumeNamePatch in Instance boot volume : %s", err) + // Add environment tags + envTags := os.Getenv("IC_ENV_TAGS") + if envTags != "" { + envTagsArray := strings.Split(envTags, ",") + userTagsArray = append(userTagsArray, envTagsArray...) } - options.VolumePatch = volumeNamePatch - _, response, err = sess.UpdateVolume(options) - eTag = response.Headers.Get("ETag") - if err != nil { - return err + + volumePatchModel := &vpcv1.VolumePatch{ + UserTags: userTagsArray, } - _, err = isWaitForInstanceBootVolumeManagerAvailable(sess, d.Id(), d.Timeout(schema.TimeoutCreate), &eTag) + volumePatch, err := volumePatchModel.AsPatch() if err != nil { - return err + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("volumePatchModel.AsPatch() failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - } - return nil -} + updateVolumeOptions := &vpcv1.UpdateVolumeOptions{ + ID: &id, + VolumePatch: volumePatch, + } -func resourceIBMISInstanceBootVolumeManagerDelete(d *schema.ResourceData, meta interface{}) error { - id := d.Id() - // check if force delete is true - if d.Get(isInstanceBootVolumeManagerDelete).(bool) { - sess, err := vpcClient(meta) + _, _, err = sess.UpdateVolumeWithContext(context, updateVolumeOptions) if err != nil { - return err + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateVolumeWithContext failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } + hasChanged = true + } - options := &vpcv1.DeleteVolumeOptions{ + // Handle access tags update + if d.HasChange(isVolumeAccessTags) { + getVolumeOptions := &vpcv1.GetVolumeOptions{ ID: &id, } - response, err := sess.DeleteVolume(options) + volume, _, err := sess.GetVolumeWithContext(context, getVolumeOptions) if err != nil { - return fmt.Errorf("[ERROR] Error deleting Volume : %s\n%s", err, response) + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetVolumeWithContext failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - _, err = isWaitForInstanceBootVolumeManagerDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) + + oldList, newList := d.GetChange(isVolumeAccessTags) + err = flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, *volume.CRN, "", isVolumeAccessTagType) if err != nil { - return err + log.Printf("Error on update of boot volume manager (%s) access tags: %s", id, err) } + hasChanged = true } - d.SetId("") - return nil -} - -func isWaitForInstanceBootVolumeManagerDeleted(vol *vpcv1.VpcV1, id string, timeout time.Duration) (interface{}, error) { - log.Printf("Waiting for (%s) to be deleted.", id) - - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", isVolumeDeleting}, - Target: []string{"done", ""}, - Refresh: isInstanceBootVolumeManagerDeleteRefreshFunc(vol, id), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } - - return stateConf.WaitForState() -} -func isInstanceBootVolumeManagerDeleteRefreshFunc(vol *vpcv1.VpcV1, id string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - volgetoptions := &vpcv1.GetVolumeOptions{ - ID: &id, + // Handle snapshot deletion if requested + if deleteAllSnapshots, ok := d.GetOk(isVolumeDeleteAllSnapshots); ok && deleteAllSnapshots.(bool) { + deleteSnapshotsOptions := &vpcv1.DeleteSnapshotsOptions{ + SourceVolumeID: &id, } - vol, response, err := vol.GetVolume(volgetoptions) + _, err := sess.DeleteSnapshotsWithContext(context, deleteSnapshotsOptions) if err != nil { - if response != nil && response.StatusCode == 404 { - return vol, isVolumeDeleted, nil - } - return vol, "", fmt.Errorf("[ERROR] Error getting Instance boot volume: %s\n%s", err, response) + log.Printf("Error deleting snapshots from boot volume (%s): %s", id, err) } - return vol, isVolumeDeleting, err } -} -func resourceIBMISInstanceBootVolumeManagerExists(d *schema.ResourceData, meta interface{}) (bool, error) { - - id := d.Id() + if hasChanged { + return resourceIBMISInstanceBootVolumeManagerRead(context, d, meta) + } - exists, err := instancebootvolExists(d, meta, id) - return exists, err + return nil } -func instancebootvolExists(d *schema.ResourceData, meta interface{}, id string) (bool, error) { +func resourceIBMISInstanceBootVolumeManagerDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { sess, err := vpcClient(meta) if err != nil { - return false, err - } - options := &vpcv1.GetVolumeOptions{ - ID: &id, + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "delete", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - _, response, err := sess.GetVolume(options) - if err != nil { - if response != nil && response.StatusCode == 404 { - return false, nil - } - return false, fmt.Errorf("[ERROR] Error getting Instance boot volume: %s\n%s", err, response) - } - return true, nil -} - -func isWaitForInstanceBootVolumeManagerAvailable(client *vpcv1.VpcV1, id string, timeout time.Duration, eTag *string) (interface{}, error) { - log.Printf("Waiting for Instance boot volume (%s) to be available.", id) - stateConf := &resource.StateChangeConf{ - Pending: []string{"retry", isVolumeProvisioning}, - Target: []string{isVolumeProvisioningDone, ""}, - Refresh: isInstanceBootVolumeManagerRefreshFunc(client, id, eTag), - Timeout: timeout, - Delay: 10 * time.Second, - MinTimeout: 10 * time.Second, - } + id := d.Id() - return stateConf.WaitForState() -} + // Check if force delete is enabled + if d.Get(isInstanceBootVolumeManagerDelete).(bool) { + // Handle snapshot deletion if requested + if deleteAllSnapshots, ok := d.GetOk(isVolumeDeleteAllSnapshots); ok && deleteAllSnapshots.(bool) { + deleteSnapshotsOptions := &vpcv1.DeleteSnapshotsOptions{ + SourceVolumeID: &id, + } + _, err := sess.DeleteSnapshotsWithContext(context, deleteSnapshotsOptions) + if err != nil { + log.Printf("Error deleting snapshots from boot volume (%s): %s", id, err) + } + } -func isInstanceBootVolumeManagerRefreshFunc(client *vpcv1.VpcV1, id string, eTag *string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - volgetoptions := &vpcv1.GetVolumeOptions{ + deleteVolumeOptions := &vpcv1.DeleteVolumeOptions{ ID: &id, } - vol, response, err := client.GetVolume(volgetoptions) + _, err := sess.DeleteVolumeWithContext(context, deleteVolumeOptions) if err != nil { - return nil, "", fmt.Errorf("[ERROR] Error getting Instance boot volume: %s\n%s", err, response) + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("DeleteVolumeWithContext failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - if *vol.Status == "available" { - return vol, isVolumeProvisioningDone, nil + _, err = isWaitForVolumeDeleted(sess, id, d.Timeout(schema.TimeoutDelete)) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("isWaitForVolumeDeleted failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } - *eTag = response.Headers.Get("ETag") - - return vol, isVolumeProvisioning, nil } + + d.SetId("") + return nil } -func deleteAllInstanceBootSnapshots(sess *vpcv1.VpcV1, id string) error { - delete_all_snapshots := new(vpcv1.DeleteSnapshotsOptions) - delete_all_snapshots.SourceVolumeID = &id - response, err := sess.DeleteSnapshots(delete_all_snapshots) +func resourceIBMISInstanceBootVolumeManagerExists(d *schema.ResourceData, meta interface{}) (bool, error) { + sess, err := vpcClient(meta) if err != nil { - return fmt.Errorf("[ERROR] Error deleting snapshots from Instance boot volume %s\n%s", err, response) + tfErr := flex.DiscriminatedTerraformErrorf(err, err.Error(), "ibm_is_instance_boot_volume_manager", "exists", "initialize-client") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return false, tfErr } - return nil + + id := d.Id() + getVolumeOptions := &vpcv1.GetVolumeOptions{ + ID: &id, + } + _, response, err := sess.GetVolume(getVolumeOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + return false, nil + } + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetVolume failed: %s", err.Error()), "ibm_is_instance_boot_volume_manager", "exists") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return false, tfErr + } + return true, nil } diff --git a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go index eada68f4e0..723f4d0e56 100644 --- a/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go +++ b/ibm/service/vpc/resource_ibm_is_instance_boot_volume_manager_test.go @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Copyright IBM Corp. 2017, 2025 All Rights Reserved. // Licensed under the Mozilla Public License v2.0 package vpc_test @@ -19,645 +19,319 @@ import ( ) func TestAccIBMISInstanceBootVolumeManager_basic(t *testing.T) { - var vol string + var volumeID string + resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMISVolumeDestroy, + CheckDestroy: testAccCheckIBMISInstanceBootVolumeManagerDestroy, Steps: []resource.TestStep{ { Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "boot_volume"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "bandwidth"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "capacity"), + resource.TestCheckResourceAttrSet( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "crn"), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "encryption_type"), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "health_state"), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "id"), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "iops"), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "name"), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "profile"), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "zone"), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "status"), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "resource_group.#"), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "volume_attachments.#"), ), }, }, }) } -func TestAccIBMISInstanceBootVolumeManager_capacity_update(t *testing.T) { - var vol string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) - capacity0 := int64(0) - capacity := int64(180) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) +func TestAccIBMISInstanceBootVolumeManager_name_update(t *testing.T) { + var volumeID string + name1 := fmt.Sprintf("tfbootvol-%d", acctest.RandIntRange(10, 100)) + name2 := fmt.Sprintf("tfbootvol-updated-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMISVolumeDestroy, + CheckDestroy: testAccCheckIBMISInstanceBootVolumeManagerDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), - ), - }, - { - Config: testAccCheckIBMISInstanceBootVolumeManagerCapacityUpdateConfig(vpcname, subnetname, sshname, publicKey, name, capacity0), + Config: testAccCheckIBMISInstanceBootVolumeManagerConfigWithName(name1), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), - resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "name", name1), ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerCapacityUpdateConfig(vpcname, subnetname, sshname, publicKey, name, capacity), + Config: testAccCheckIBMISInstanceBootVolumeManagerConfigWithName(name2), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), - resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "capacity", fmt.Sprintf("%d", capacity)), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "name", name2), ), }, }, }) } -func TestAccIBMISInstanceBootVolumeManager_profile_update(t *testing.T) { - var vol string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) - profile0 := "" - profile := "10iops-tier" - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + +func TestAccIBMISInstanceBootVolumeManager_capacity_update(t *testing.T) { + var volumeID string + capacity1 := 120 + capacity2 := 180 + resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMISVolumeDestroy, + CheckDestroy: testAccCheckIBMISInstanceBootVolumeManagerDestroy, Steps: []resource.TestStep{ { Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "capacity"), ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerProfileUpdateConfig(vpcname, subnetname, sshname, publicKey, name, profile0), + Config: testAccCheckIBMISInstanceBootVolumeManagerConfigWithCapacity(capacity1), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), - resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "capacity", fmt.Sprintf("%d", capacity1)), ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerProfileUpdateConfig(vpcname, subnetname, sshname, publicKey, name, profile), + Config: testAccCheckIBMISInstanceBootVolumeManagerConfigWithCapacity(capacity2), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), - resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "profile", profile), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "capacity", fmt.Sprintf("%d", capacity2)), ), }, }, }) } -func TestAccIBMISInstanceBootVolumeManager_all_update(t *testing.T) { - var vol string - vpcname := fmt.Sprintf("tf-vpc-%d", acctest.RandIntRange(10, 100)) - name := fmt.Sprintf("tf-server-%d", acctest.RandIntRange(10, 100)) - volname := fmt.Sprintf("tf-vol-%d", acctest.RandIntRange(10, 100)) - subnetname := fmt.Sprintf("tfip-subnet-%d", acctest.RandIntRange(10, 100)) + +func TestAccIBMISInstanceBootVolumeManager_profile_update(t *testing.T) { + var volumeID string profile := "10iops-tier" - capacity := int64(200) - tag1 := "env:prod" - tag2 := "boot:unattached" - tag3 := "delete:false" - accesstag := "access:qa" - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshname := fmt.Sprintf("tf-sshname-%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMISVolumeDestroy, + CheckDestroy: testAccCheckIBMISInstanceBootVolumeManagerDestroy, Steps: []resource.TestStep{ { Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "profile"), ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerAllUpdateConfig(vpcname, subnetname, sshname, publicKey, name, "", tag1, tag2, "", "", "", 0), + Config: testAccCheckIBMISInstanceBootVolumeManagerConfigWithProfile(profile), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), - resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), - ), - }, - { - Config: testAccCheckIBMISInstanceBootVolumeManagerAllUpdateConfig(vpcname, subnetname, sshname, publicKey, name, profile, tag1, tag2, tag3, accesstag, volname, capacity), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), - resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "access_tags.#", "1"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "access_tags.#", "1"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "profile", profile), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "name", volname), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "capacity", fmt.Sprintf("%d", capacity)), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "profile", profile), ), }, }, }) } -func TestAccIBMISInstanceBootVolumeManager_name_update(t *testing.T) { - var vol string - name1 := fmt.Sprintf("tfbootvoluat-%d", acctest.RandIntRange(10, 100)) - name2 := fmt.Sprintf("tfbootvoluat-%d", acctest.RandIntRange(10, 100)) +func TestAccIBMISInstanceBootVolumeManager_iops_update(t *testing.T) { + var volumeID string + iops1 := 600 + iops2 := 900 + resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMISVolumeDestroy, + CheckDestroy: testAccCheckIBMISInstanceBootVolumeManagerDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), + Config: testAccCheckIBMISInstanceBootVolumeManagerConfigWithIOPS("custom", iops1), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "iops", fmt.Sprintf("%d", iops1)), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "profile", "custom"), ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerNameUpdateConfig(name1), + Config: testAccCheckIBMISInstanceBootVolumeManagerConfigWithIOPS("custom", iops2), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "iops", fmt.Sprintf("%d", iops2)), resource.TestCheckResourceAttr( - "ibm_is_instance_boot_volume_manager.boot", "name", name1), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "profile", "custom"), ), }, + }, + }) +} + +func TestAccIBMISInstanceBootVolumeManager_tags(t *testing.T) { + var volumeID string + tag1 := "env:test" + tag2 := "team:dev" + tag3 := "boot:managed" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISInstanceBootVolumeManagerDestroy, + Steps: []resource.TestStep{ { - Config: testAccCheckIBMISInstanceBootVolumeManagerNameUpdateConfig(name2), + Config: testAccCheckIBMISInstanceBootVolumeManagerConfigWithTags(tag1, tag2), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "tags.#", "2"), + ), + }, + { + Config: testAccCheckIBMISInstanceBootVolumeManagerConfigWithTags(tag1, tag2, tag3), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), resource.TestCheckResourceAttr( - "ibm_is_instance_boot_volume_manager.boot", "name", name2), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "tags.#", "3"), ), }, }, }) } -func TestAccIBMISInstanceBootVolumeManager_accesstag_update(t *testing.T) { - var vol string - tag1 := "access:qa" + +func TestAccIBMISInstanceBootVolumeManager_access_tags(t *testing.T) { + var volumeID string + accessTag := "project:test" + resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMISVolumeDestroy, + CheckDestroy: testAccCheckIBMISInstanceBootVolumeManagerDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), + Config: testAccCheckIBMISInstanceBootVolumeManagerConfigWithAccessTags(accessTag), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "access_tags.#", "1"), ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerAccessTagUpdateConfig(tag1), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), - resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "access_tags.#"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "access_tags.#", "1"), - ), + ResourceName: "ibm_is_instance_boot_volume_manager.test_boot_volume", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"delete_volume", "delete_all_snapshots"}, }, }, }) } -func TestAccIBMISInstanceBootVolumeManagerUsertag_basic(t *testing.T) { - var vol string + +func TestAccIBMISInstanceBootVolumeManager_complete_update(t *testing.T) { + var volumeID string + name := fmt.Sprintf("tfbootvol-%d", acctest.RandIntRange(10, 100)) + updatedName := fmt.Sprintf("tfbootvol-updated-%d", acctest.RandIntRange(10, 100)) + profile := "10iops-tier" + capacity := 200 tag1 := "env:prod" - tag2 := "boot:unattached" - tag3 := "delete:false" + tag2 := "boot:managed" + accessTag := "project:production" + resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMISVolumeDestroy, + CheckDestroy: testAccCheckIBMISInstanceBootVolumeManagerDestroy, Steps: []resource.TestStep{ { Config: testAccCheckIBMISInstanceBootVolumeManagerConfig(), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "name"), ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, ""), + Config: testAccCheckIBMISInstanceBootVolumeManagerCompleteConfig(name, profile, capacity, tag1, tag2, accessTag), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), - resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "2"), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "name", name), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "profile", profile), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "capacity", fmt.Sprintf("%d", capacity)), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "tags.#", "2"), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "access_tags.#", "1"), ), }, { - Config: testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, tag3), + Config: testAccCheckIBMISInstanceBootVolumeManagerCompleteConfig(updatedName, profile, capacity+50, tag1, tag2, accessTag), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "bandwidth"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "capacity"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "crn"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "encryption_type"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "health_state"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "id"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "iops"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "name"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "profile"), - resource.TestCheckResourceAttrSet( - "ibm_is_instance_boot_volume_manager.boot", "zone"), - resource.TestCheckResourceAttrSet("ibm_is_instance_boot_volume_manager.boot", "tags.#"), - resource.TestCheckResourceAttr("ibm_is_instance_boot_volume_manager.boot", "tags.#", "3"), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "name", updatedName), + resource.TestCheckResourceAttr( + "ibm_is_instance_boot_volume_manager.test_boot_volume", "capacity", fmt.Sprintf("%d", capacity+50)), ), }, }, }) } -func TestAccIBMISInstanceBootVolumeManagerDelete_basic(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)) +func TestAccIBMISInstanceBootVolumeManager_delete_volume(t *testing.T) { + var volumeID string + vpcName := fmt.Sprintf("tfvpc-%d", acctest.RandIntRange(10, 100)) + subnetName := fmt.Sprintf("tfsubnet-%d", acctest.RandIntRange(10, 100)) + sshName := fmt.Sprintf("tfssh-%d", acctest.RandIntRange(10, 100)) + instanceName := fmt.Sprintf("tfinstance-%d", acctest.RandIntRange(10, 100)) + bootVolumeName := fmt.Sprintf("tfbootvol-%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)) - iops1 := int64(600) - iops2 := int64(900) resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, - CheckDestroy: testAccCheckIBMISVolumeDestroy, + CheckDestroy: testAccCheckIBMISInstanceBootVolumeManagerDestroyWithDeletion, Steps: []resource.TestStep{ { - Config: testAccCheckIBMISVolumeCustomConfig(vpcname, subnetname, sshname, publicKey, name, volName, iops1), + Config: testAccCheckIBMISInstanceBootVolumeManagerConfigWithDeletion(vpcName, subnetName, sshName, publicKey, instanceName, bootVolumeName), Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), + testAccCheckIBMISInstanceBootVolumeManagerExists("ibm_is_instance_boot_volume_manager.test_boot_volume", volumeID), resource.TestCheckResourceAttr( - "ibm_is_instance_boot_volume_manager.boot", "name", volName), - resource.TestCheckResourceAttr( - "ibm_is_instance_boot_volume_manager.boot", "iops", fmt.Sprintf("%d", iops1)), - ), - }, - - { - Config: testAccCheckIBMISVolumeCustomConfig(vpcname, subnetname, sshname, publicKey, name, volName, iops2), - Check: resource.ComposeTestCheckFunc( - testAccCheckIBMISVolumeExists("ibm_is_instance_boot_volume_manager.boot", vol), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "name", bootVolumeName), resource.TestCheckResourceAttr( - "ibm_is_instance_boot_volume_manager.boot", "name", volName), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "delete_volume", "true"), resource.TestCheckResourceAttr( - "ibm_is_instance_boot_volume_manager.boot", "iops", fmt.Sprintf("%d", iops2)), + "ibm_is_instance_boot_volume_manager.test_boot_volume", "delete_all_snapshots", "true"), ), }, }, @@ -665,27 +339,51 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE } func testAccCheckIBMISInstanceBootVolumeManagerDestroy(s *terraform.State) error { - sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { - if rs.Type != "ibm_is_vol" { + if rs.Type != "ibm_is_instance_boot_volume_manager" { continue } - getvolumeoptions := &vpcv1.GetVolumeOptions{ + getVolumeOptions := &vpcv1.GetVolumeOptions{ ID: &rs.Primary.ID, } - _, _, err := sess.GetVolume(getvolumeoptions) + _, response, err := sess.GetVolume(getVolumeOptions) if err == nil { - return fmt.Errorf("[ERROR] Volume still exists: %s", rs.Primary.ID) + // Volume still exists, which is expected if delete_volume was false + continue + } + if response != nil && response.StatusCode != 404 { + return fmt.Errorf("Error checking for boot volume (%s) deletion: %s", rs.Primary.ID, err) } } + return nil +} +func testAccCheckIBMISInstanceBootVolumeManagerDestroyWithDeletion(s *terraform.State) error { + sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_is_instance_boot_volume_manager" { + continue + } + + getVolumeOptions := &vpcv1.GetVolumeOptions{ + ID: &rs.Primary.ID, + } + _, response, err := sess.GetVolume(getVolumeOptions) + + if err == nil { + return fmt.Errorf("Boot volume still exists: %s", rs.Primary.ID) + } + if response != nil && response.StatusCode != 404 { + return fmt.Errorf("Error checking for boot volume (%s) deletion: %s", rs.Primary.ID, err) + } + } return nil } -func testAccCheckIBMISInstanceBootVolumeManagerExists(n, volID string) resource.TestCheckFunc { +func testAccCheckIBMISInstanceBootVolumeManagerExists(n, volumeID string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -698,243 +396,135 @@ func testAccCheckIBMISInstanceBootVolumeManagerExists(n, volID string) resource. } sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() - getvolumeoptions := &vpcv1.GetVolumeOptions{ + getVolumeOptions := &vpcv1.GetVolumeOptions{ ID: &rs.Primary.ID, } - foundvol, _, err := sess.GetVolume(getvolumeoptions) + foundVolume, _, err := sess.GetVolume(getVolumeOptions) if err != nil { return err } - volID = *foundvol.ID + volumeID = *foundVolume.ID return nil } } func testAccCheckIBMISInstanceBootVolumeManagerConfig() string { - return fmt.Sprintf( - ` - resource "ibm_is_instance_boot_volume_manager" "boot"{ - volume_id = "%s" - } -`, acc.VSIUnattachedBootVolumeID) - + return fmt.Sprintf(` +resource "ibm_is_instance_boot_volume_manager" "test_boot_volume" { + boot_volume = "%s" +}`, acc.VSIUnattachedBootVolumeID) } -func testAccCheckIBMISInstanceBootVolumeManagerNameUpdateConfig(name string) string { - return fmt.Sprintf( - ` - resource "ibm_is_instance_boot_volume_manager" "boot"{ - volume_id = "%s" - name = "%s" - } -`, acc.VSIUnattachedBootVolumeID, name) - +func testAccCheckIBMISInstanceBootVolumeManagerConfigWithName(name string) string { + return fmt.Sprintf(` +resource "ibm_is_instance_boot_volume_manager" "test_boot_volume" { + boot_volume = "%s" + name = "%s" +}`, acc.VSIUnattachedBootVolumeID, name) } -func testAccCheckIBMISInstanceBootVolumeManagerTagUpdateConfig(tag1, tag2, tag3 string) string { - return fmt.Sprintf( - ` - resource "ibm_is_instance_boot_volume_manager" "boot"{ - volume_id = "%s" - tags = "%s" == "" ? ["%s", "%s"] : ["%s", "%s", "%s"] - } -`, acc.VSIUnattachedBootVolumeID, tag3, tag1, tag2, tag1, tag2, tag3) - +func testAccCheckIBMISInstanceBootVolumeManagerConfigWithCapacity(capacity int) string { + return fmt.Sprintf(` +resource "ibm_is_instance_boot_volume_manager" "test_boot_volume" { + boot_volume = "%s" + capacity = %d +}`, acc.VSIUnattachedBootVolumeID, capacity) } -func testAccCheckIBMISInstanceBootVolumeManagerAccessTagUpdateConfig(tag1 string) string { - return fmt.Sprintf( - ` - resource "ibm_is_instance_boot_volume_manager" "boot"{ - volume_id = "%s" - access_tags = ["%s"] - } -`, acc.VSIUnattachedBootVolumeID, tag1) +func testAccCheckIBMISInstanceBootVolumeManagerConfigWithProfile(profile string) string { + return fmt.Sprintf(` +resource "ibm_is_instance_boot_volume_manager" "test_boot_volume" { + boot_volume = "%s" + profile = "%s" +}`, acc.VSIUnattachedBootVolumeID, profile) } -func testAccCheckIBMISInstanceBootVolumeManagerCapacityUpdateConfig(vpcname, subnetname, sshname, publicKey, name string, capacity int64) string { - return fmt.Sprintf( - ` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - total_ipv4_address_count = 16 - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - profile = "%s" - boot_volume { - volume_id = ibm_is_instance_boot_volume_manager.boot.id - auto_delete_volume = false - } - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - } - resource "ibm_is_instance_boot_volume_manager" "boot" { - volume_id = "%s" - capacity = %d == 0 ? null : %d - } - `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.InstanceProfileName, acc.ISZoneName, acc.VSIUnattachedBootVolumeID, capacity, capacity) +func testAccCheckIBMISInstanceBootVolumeManagerConfigWithIOPS(profile string, iops int) string { + return fmt.Sprintf(` +resource "ibm_is_instance_boot_volume_manager" "test_boot_volume" { + boot_volume = "%s" + profile = "%s" + iops = %d +}`, acc.VSIUnattachedBootVolumeID, profile, iops) +} +func testAccCheckIBMISInstanceBootVolumeManagerConfigWithTags(tags ...string) string { + tagList := `["` + strings.Join(tags, `", "`) + `"]` + return fmt.Sprintf(` +resource "ibm_is_instance_boot_volume_manager" "test_boot_volume" { + boot_volume = "%s" + tags = %s +}`, acc.VSIUnattachedBootVolumeID, tagList) } -func testAccCheckIBMISInstanceBootVolumeManagerProfileUpdateConfig(vpcname, subnetname, sshname, publicKey, name, profile string) string { - return fmt.Sprintf( - ` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - total_ipv4_address_count = 16 - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - profile = "%s" - boot_volume { - volume_id = ibm_is_instance_boot_volume_manager.boot.id - auto_delete_volume = false - } - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - } - resource "ibm_is_instance_boot_volume_manager" "boot" { - volume_id = "%s" - profile = "%s" == "" ? null : "%s" - } - `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.InstanceProfileName, acc.ISZoneName, acc.VSIUnattachedBootVolumeID, profile, profile) +func testAccCheckIBMISInstanceBootVolumeManagerConfigWithAccessTags(accessTag string) string { + return fmt.Sprintf(` +resource "ibm_is_instance_boot_volume_manager" "test_boot_volume" { + boot_volume = "%s" + access_tags = ["%s"] +}`, acc.VSIUnattachedBootVolumeID, accessTag) } -func testAccCheckIBMISInstanceBootVolumeManagerAllUpdateConfig(vpcname, subnetname, sshname, publicKey, name, profile, tag1, tag2, tag3, accesstag, volname string, capacity int64) string { - return fmt.Sprintf( - ` - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - total_ipv4_address_count = 16 - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - profile = "%s" - boot_volume { - volume_id = ibm_is_instance_boot_volume_manager.boot.id - auto_delete_volume = false - } - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - } - resource "ibm_is_instance_boot_volume_manager" "boot" { - volume_id = "%s" - profile = "%s" == "" ? null : "%s" - capacity = %d == 0 ? null : %d - access_tags = "%s" == "" ? null : ["%s"] - tags = "%s" == "" ? null : ["%s", "%s", "%s"] - name = "%s" == "" ? null : "%s" - } - `, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, name, acc.InstanceProfileName, acc.ISZoneName, acc.VSIUnattachedBootVolumeID, profile, profile, capacity, capacity, accesstag, accesstag, tag3, tag1, tag2, tag3, volname, volname) +func testAccCheckIBMISInstanceBootVolumeManagerCompleteConfig(name, profile string, capacity int, tag1, tag2, accessTag string) string { + return fmt.Sprintf(` +resource "ibm_is_instance_boot_volume_manager" "test_boot_volume" { + boot_volume = "%s" + name = "%s" + profile = "%s" + capacity = %d + tags = ["%s", "%s"] + access_tags = ["%s"] +}`, acc.VSIUnattachedBootVolumeID, name, profile, capacity, tag1, tag2, accessTag) } -func testAccCheckIBMISInstanceBootVolumeManagerAttachmentDeleteConfig(vpcname, subnetname, sshname, publicKey, insname, capacityArray string) string { - return fmt.Sprintf( - ` - variable "vsi_vol_size" { - description = "capacity array" - default = %s - } +func testAccCheckIBMISInstanceBootVolumeManagerConfigWithDeletion(vpcName, subnetName, sshName, publicKey, instanceName, bootVolumeName string) string { + return fmt.Sprintf(` +resource "ibm_is_vpc" "test_vpc" { + name = "%s" +} - resource "ibm_is_volume" "storage"{ - name = "tf-vol-att-${count.index}" - count = length(var.vsi_vol_size) - profile = "general-purpose" - zone = "%s" - capacity = var.vsi_vol_size[count.index] - } +resource "ibm_is_subnet" "test_subnet" { + name = "%s" + vpc = ibm_is_vpc.test_vpc.id + zone = "%s" + total_ipv4_address_count = 16 +} - resource "ibm_is_vpc" "testacc_vpc" { - name = "%s" - } - - resource "ibm_is_subnet" "testacc_subnet" { - name = "%s" - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - total_ipv4_address_count = 16 - } - - resource "ibm_is_ssh_key" "testacc_sshkey" { - name = "%s" - public_key = "%s" - } - - resource "ibm_is_instance" "testacc_instance" { - name = "%s" - image = "%s" - profile = "%s" - volumes = ibm_is_instance_boot_volume_manager.boot[*].id - primary_network_interface { - subnet = ibm_is_subnet.testacc_subnet.id - } - vpc = ibm_is_vpc.testacc_vpc.id - zone = "%s" - keys = [ibm_is_ssh_key.testacc_sshkey.id] - } -`, capacityArray, acc.ISZoneName, vpcname, subnetname, acc.ISZoneName, sshname, publicKey, insname, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName) +resource "ibm_is_ssh_key" "test_ssh_key" { + name = "%s" + public_key = "%s" +} +resource "ibm_is_volume" "test_boot_volume" { + name = "%s" + profile = "general-purpose" + zone = "%s" + capacity = 100 } -func testAccCheckIBMISInstanceBootVolumeManagerUsertagConfig(name, usertag string) string { - return fmt.Sprintf( - ` - resource "ibm_is_volume" "storage"{ - name = "%s" - profile = "10iops-tier" - zone = "us-south-1" - # capacity= 200 - tags = ["%s"] - } -`, name, usertag) +resource "ibm_is_instance" "test_instance" { + name = "%s" + image = "%s" + profile = "%s" + + boot_volume { + volume_id = ibm_is_instance_boot_volume_manager.test_boot_volume.id + auto_delete_volume = false + } + + primary_network_interface { + subnet = ibm_is_subnet.test_subnet.id + } + + vpc = ibm_is_vpc.test_vpc.id + zone = "%s" + keys = [ibm_is_ssh_key.test_ssh_key.id] +} +resource "ibm_is_instance_boot_volume_manager" "test_boot_volume" { + boot_volume = ibm_is_volume.test_boot_volume.id + name = "%s" + delete_volume = true + delete_all_snapshots = true +}`, vpcName, subnetName, acc.ISZoneName, sshName, publicKey, bootVolumeName, acc.ISZoneName, instanceName, acc.IsImage, acc.InstanceProfileName, acc.ISZoneName, bootVolumeName) } diff --git a/website/docs/r/is_instance_boot_volume_manager.html.markdown b/website/docs/r/is_instance_boot_volume_manager.html.markdown index ec5d4eca1f..9deea01a15 100644 --- a/website/docs/r/is_instance_boot_volume_manager.html.markdown +++ b/website/docs/r/is_instance_boot_volume_manager.html.markdown @@ -2,21 +2,25 @@ subcategory: "VPC infrastructure" layout: "ibm" -page_title: "IBM : instance_boot_volume_manager" +page_title: "IBM : ibm_is_instance_boot_volume_manager" description: |- - Manages IBM instance boot volume. + Manages IBM VPC instance boot volume. --- # ibm_is_instance_boot_volume_manager -Provides a resource to manage a boot volume of a VPC virtual server instance. Manage the boot volume of a VPC virtual server instance created alongwith the instance creation with this resource. + +Provides a resource to manage the boot volume of a VPC virtual server instance. This resource allows you to manage boot volumes that may have been orphaned or need to be managed independently of their instance lifecycle. ~> **NOTE:** This is an advanced resource with special caveats. Please read this document in its entirety before using this resource. The `ibm_is_instance_boot_volume_manager` resource behaves differently from normal resources. Terraform does not _create_ this resource but instead attempts to "adopt" it into management. -Every Virtual server instance has a boot volume that needs to be managed but not destroyed. When Terraform first adopts a instance_boot_volume_manager, +This resource is particularly useful for managing boot volumes that: +- Have been orphaned after instance deletion +- Need independent lifecycle management from their instance +- Require specific configuration changes that affect the boot volume properties -For more information, about VPC, see [getting started with Virtual Private Cloud](https://cloud.ibm.com/docs/vpc?topic=vpc-getting-started). For more information, about updating default security group, see [updating a VPC's default security group rules](https://cloud.ibm.com/docs/vpc?topic=vpc-updating-the-default-security-group&interface=ui). +For more information, about VPC virtual server instances, see [getting started with Virtual Private Cloud](https://cloud.ibm.com/docs/vpc?topic=vpc-getting-started). For more information about VPC storage, see [About Block Storage for VPC](https://cloud.ibm.com/docs/vpc?topic=vpc-block-storage-about). -~> **NOTE:** +**Note:** VPC infrastructure services are a regional specific based endpoint, by default targets to `us-south`. Please make sure to target right region in the provider block as shown in the `provider.tf` file, if VPC service is created in region other than `us-south`. **provider.tf** @@ -28,95 +32,225 @@ provider "ibm" { ``` ## Example usage -The following example manages a boot volume with 10 IOPs tier. +### Basic boot volume management ```terraform resource "ibm_is_instance_boot_volume_manager" "example" { - volume_id = "r006-10cc2ee8-f395-47a1-b043-4e7a855a6dd0" - name = "example-volume" + boot_volume = "r006-10cc2ee8-f395-47a1-b043-4e7a855a6dd0" + name = "my-managed-boot-volume" +} +``` + +### Boot volume with performance configuration +```terraform +resource "ibm_is_instance_boot_volume_manager" "example" { + boot_volume = "r006-10cc2ee8-f395-47a1-b043-4e7a855a6dd0" + name = "high-performance-boot" profile = "10iops-tier" + capacity = 120 + iops = 3000 } ``` -## Timeouts -The `ibm_is_instance_boot_volume_manager` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: +### Boot volume with tags and conditional deletion +```terraform +resource "ibm_is_instance_boot_volume_manager" "example" { + boot_volume = "r006-10cc2ee8-f395-47a1-b043-4e7a855a6dd0" + name = "managed-boot-volume" + profile = "10iops-tier" + tags = ["env:production", "managed:terraform"] + access_tags = ["project:web-app"] + delete_volume = true + delete_all_snapshots = true +} +``` + +### Managing boot volume from instance +```terraform +resource "ibm_is_instance" "example" { + name = "example-instance" + image = "r006-14140f94-fcc4-11e9-96e7-a72723715315" + profile = "bx2-2x8" -- **create** - (Default 10 minutes) Used for creating instance. -- **delete** - (Default 10 minutes) Used for deleting instance. + primary_network_interface { + subnet = ibm_is_subnet.example.id + } + vpc = ibm_is_vpc.example.id + zone = "us-south-1" + keys = [ibm_is_ssh_key.example.id] +} + +resource "ibm_is_instance_boot_volume_manager" "example" { + boot_volume = ibm_is_instance.example.boot_volume[0].volume_id + name = "managed-boot-volume" + profile = "10iops-tier" + delete_volume = false # Don't delete when resource is destroyed +} +``` ## Argument reference -Review the argument references that you can specify for your resource. +Review the argument references that you can specify for your resource. -- `access_tags` - (Optional, List of Strings) A list of access management tags to attach to the bare metal server. +- `access_tags` - (Optional, List of Strings) A list of access management tags to attach to the boot volume. ~> **Note:** **•** You can attach only those access tags that already exists.
**•** For more information, about creating access tags, see [working with tags](https://cloud.ibm.com/docs/account?topic=account-tag&interface=ui#create-access-console).
**•** You must have the access listed in the [Granting users access to tag resources](https://cloud.ibm.com/docs/account?topic=account-access) for `access_tags`
**•** `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.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. +- `boot_volume` - (Required, Forces new resource, String) The unique identifier for the boot volume. +- `capacity` - (Optional, Integer) The capacity of the volume in gigabytes. The minimum capacity is 10 GB and the maximum capacity is 16,000 GB. -- `delete_all_snapshots` - (Optional, Bool) Deletes all snapshots created from this volume. -- `iops` - (Optional, Integer) The total input/ output operations per second (IOPS) for your storage. This value is required for `custom` storage profiles only. + ~> **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 a running virtual server instance. Stopped instance will be started automatically on update of capacity. +- `delete_all_snapshots` - (Optional, Boolean) If set to true, all snapshots created from this volume will be deleted when the volume is deleted. Default value is `false`. +- `delete_volume` - (Optional, Boolean) If set to true, the boot volume will be deleted when this resource is destroyed. Default value is `false`. +- `iops` - (Optional, Integer) The maximum I/O operations per second (IOPS) for the volume. This value is required for `custom` storage profiles only. - ~> **NOTE:** `iops` value can be upgraded and downgraged if volume is attached to an running virtual server instance. Stopped instances will be started on update of volume. + ~> **NOTE:** `iops` value can be upgraded and downgraded if volume is attached to a running virtual server instance. Stopped instances will be started automatically on update of volume. This table shows how storage size affects the `iops` ranges: - | Size range (GB) | IOPS range | - |--------------------|----------------| - | 10 - 39 | 100 - 1000 | - | 40 - 79 | 100 - 2000 | - | 80 - 99 | 100 - 4000 | - | 100 - 499 | 100 - 6000 | - | 500 - 999 | 100 - 10000 | - | 1000 - 1999 | 100 - 20000 | - | 2000 - 3999 | 100 - 40000 | - | 4000 - 1999 | 100 - 40000 | - | 8000 - 1999 | 100 - 48000 | - | 10000 - 16000 | 100 - 48000 | + | Size range (GB) | IOPS range | + |--------------------|----------------| + | 10 - 39 | 100 - 1000 | + | 40 - 79 | 100 - 2000 | + | 80 - 99 | 100 - 4000 | + | 100 - 499 | 100 - 6000 | + | 500 - 999 | 100 - 10000 | + | 1000 - 1999 | 100 - 20000 | + | 2000 - 3999 | 100 - 40000 | + | 4000 - 7999 | 100 - 40000 | + | 8000 - 9999 | 100 - 48000 | + | 10000 - 16000 | 100 - 48000 | -- `name` - (Required, String) The user-defined name for this volume.No. -- `profile` - (Required, String) The profile to use for this volume. +- `name` - (Optional, String) The user-defined name for this boot volume. If unspecified, the name will be automatically assigned. +- `profile` - (Optional, String) The globally unique name of the volume profile to use for this volume. Valid profiles are `general-purpose`, `5iops-tier`, `10iops-tier`, and `custom`. - ~> **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. - -- `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) -- `volume_id` - (Required, Forces new resource, String) The volume id of the volume from boot volume. + ~> **NOTE:** Tiered profiles [`general-purpose`, `5iops-tier`, `10iops-tier`] can be upgraded and downgraded into each other if volume is attached to a running virtual server instance. Stopped instances will be started automatically on update of volume. +- `tags` - (Optional, List of Strings) User tags for the boot volume. ## Attribute reference In addition to all argument reference list, you can access the following attribute reference after your resource is created. -- `bandwidth` - (Integer) The maximum bandwidth (in megabits per second) for the volume -- `encryption_type` - (String) The type of encryption used in the volume [**provider_managed**, **user_managed**]. + +- `bandwidth` - (Integer) The maximum bandwidth (in megabits per second) for the volume. +- `crn` - (String) The CRN for the volume. +- `encryption_key` - (String) The CRN of the encryption key used to encrypt this volume. +- `encryption_type` - (String) The type of encryption used on the volume. - `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. +- `health_state` - (String) The health state of this volume. - `id` - (String) The unique identifier of the volume. +- `resource_group` - (List) The resource group for this volume. + + Nested scheme for `resource_group`: + - `href` - (String) The URL for this resource group. + - `id` - (String) The unique identifier for this resource group. + - `name` - (String) The user-defined name for this resource group. +- `source_snapshot` - (String) The unique identifier for the snapshot from which this volume was created. - `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. Nested scheme for `status_reasons`: - `code` - (String) A string with an underscore as a special character identifying the status reason. - `message` - (String) An explanation of the status reason. - - `more_info` - (String) Link to documentation about this status reason -- `crn` - (String) The CRN for the volume. -- `encryption_key` - (String) The key to use for encrypting this volume. -- `resource_group` - (String) The resource group ID for this volume. -- `source_snapshot` - (String) The ID of snapshot from which to clone the volume. -- `zone` - (String) The location of the volume. + - `more_info` - (String) Link to documentation about this status reason. +- `volume_attachments` - (List) The volume attachments for this volume. + + Nested scheme for `volume_attachments`: + - `delete_volume_on_instance_delete` - (Boolean) If set to true, this volume will be deleted when the instance is deleted. + - `device` - (List) Information about how the volume is exposed to the instance operating system. + + Nested scheme for `device`: + - `id` - (String) A unique identifier for the device which is exposed to the instance operating system. + - `href` - (String) The URL for this volume attachment. + - `id` - (String) The unique identifier for this volume attachment. + - `instance` - (List) The attached instance. + + Nested scheme for `instance`: + - `crn` - (String) The CRN for this virtual server instance. + - `href` - (String) The URL for this virtual server instance. + - `id` - (String) The unique identifier for this virtual server instance. + - `name` - (String) The user-defined name for this virtual server instance. + - `name` - (String) The user-defined name for this volume attachment. + - `type` - (String) The type of volume attachment. +- `zone` - (String) The zone where this volume resides. + +## Timeouts +The `ibm_is_instance_boot_volume_manager` resource provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 10 minutes) Used for adopting the boot volume. +- **update** - (Default 10 minutes) Used for updating boot volume properties. +- **delete** - (Default 10 minutes) Used for deleting boot volume (when `delete_volume` is true). ## Import -The `ibm_is_instance_boot_volume_manager` resource can be imported by using volume ID. +The `ibm_is_instance_boot_volume_manager` resource can be imported by using the boot volume ID. + +**Syntax** + +``` +$ terraform import ibm_is_instance_boot_volume_manager.example +``` **Example** ``` $ terraform import ibm_is_instance_boot_volume_manager.example d7bec597-4726-451f-8a63-e62e6f19c32c ``` + +## Usage scenarios + +### Orphaned boot volume management +When an instance is deleted but the boot volume remains (either by design or accident), you can use this resource to manage the orphaned volume: + +```terraform +resource "ibm_is_instance_boot_volume_manager" "orphaned_volume" { + boot_volume = "r006-orphaned-volume-id" + name = "recovered-boot-volume" + profile = "10iops-tier" + delete_volume = true # Clean up when done +} +``` + +### Instance-independent management +Manage boot volume properties independently of the instance lifecycle: + +```terraform +# Instance with minimal boot volume configuration +resource "ibm_is_instance" "app_server" { + name = "app-server" + # ... other configuration +} + +# Separate management of the boot volume +resource "ibm_is_instance_boot_volume_manager" "boot_config" { + boot_volume = ibm_is_instance.app_server.boot_volume[0].volume_id + name = "app-server-boot-managed" + profile = "10iops-tier" + tags = ["env:production", "managed:terraform"] + delete_volume = false # Keep volume when resource is destroyed + delete_all_snapshots = false # Preserve snapshots +} +``` + +## Important notes + +- **Instance state management**: When updating volume properties like capacity, profile, or IOPS, the attached instance must be running. This resource will automatically start stopped instances when necessary for updates. +- **Boot volume lifecycle**: Boot volumes cannot be detached from running instances. This resource manages the volume properties while it remains attached. +- **Deletion behavior**: By default, this resource does not delete the actual boot volume when destroyed (only removes it from Terraform state). Set `delete_volume = true` to actually delete the volume. +- **Snapshot management**: Set `delete_all_snapshots = true` to automatically clean up all snapshots when the volume is deleted. +- **Performance updates**: Volume performance characteristics (profile, IOPS, capacity) can be modified while the volume is in use, but may require brief instance restart. +- **Profile compatibility**: Some profile changes require specific IOPS values. Refer to the IOPS table for valid combinations. + +## Error handling + +Common scenarios and resolutions: + +- **Volume not found**: Ensure the boot volume ID is correct and the volume exists in the target region. +- **Volume attached to running instance**: Some operations require the instance to be running. The resource will attempt to start stopped instances automatically. +- **Invalid IOPS for profile**: Ensure IOPS values are within the valid range for the selected profile and capacity. +- **Capacity decrease**: Boot volume capacity can only be increased, never decreased.