alibabacloudstack/resource_apsarastack_ecs_disk.go (344 lines of code) (raw):

package alibabacloudstack import ( "errors" "os" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/terraform-provider-alibabacloudstack/alibabacloudstack/connectivity" "github.com/aliyun/terraform-provider-alibabacloudstack/alibabacloudstack/errmsgs" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func resourceAlibabacloudStackDisk() *schema.Resource { resource := &schema.Resource{ Schema: map[string]*schema.Schema{ "availability_zone": { Type: schema.TypeString, ForceNew: true, Optional: true, Computed: true, Deprecated: "Field 'availability_zone' is deprecated and will be removed in a future release. Please use new field 'zone_id' instead.", ConflictsWith: []string{"zone_id"}, }, "zone_id": { Type: schema.TypeString, ForceNew: true, Optional: true, Computed: true, ConflictsWith: []string{"availability_zone"}, }, "name": { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: validation.StringLenBetween(2, 128), Deprecated: "Field 'name' is deprecated and will be removed in a future release. Please use new field 'disk_name' instead.", ConflictsWith: []string{"disk_name"}, }, "disk_name": { Type: schema.TypeString, Optional: true, Computed: true, ValidateFunc: validation.StringLenBetween(2, 128), ConflictsWith: []string{"name"}, }, "description": { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringLenBetween(2, 256), }, "category": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{"cloud", "cloud_efficiency", "cloud_ssd", "cloud_pperf", "cloud_sperf"}, false), Default: DiskCloudEfficiency, }, "size": { Type: schema.TypeInt, Optional: true, }, "snapshot_id": { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"encrypted"}, }, "kms_key_id": { Type: schema.TypeString, Optional: true, }, "encrypted": { Type: schema.TypeBool, Optional: true, ForceNew: true, ConflictsWith: []string{"snapshot_id"}, }, "encrypt_algorithm": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{"sm4-128", "aes-256"}, false), DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { // 无法直接读取 encrypted 的当前值,只能通过 ResourceData 获取可能不准确的状态 if encrypted := d.Get("encrypted").(bool); !encrypted { return true } else if v, err := stringToBool(os.Getenv("APSARASTACK_IN_ALIBABACLOUDSTACK")); err != nil && v { if (old == "aes-256" && new == "") || (old == "" && new == "aes-256") { // 如果是APSARASTACK迁移模式,aes-256改""不触发变更 return true } } return !d.HasChange("encrypt_algorithm") }, }, "delete_auto_snapshot": { Type: schema.TypeBool, Optional: true, Default: false, }, "delete_with_instance": { Type: schema.TypeBool, Optional: true, Default: false, }, "enable_auto_snapshot": { Type: schema.TypeBool, Optional: true, Default: false, }, "status": { Type: schema.TypeString, Computed: true, }, "auto_snapshot_policy_id": { Type: schema.TypeString, Computed: true, }, "enable_automated_snapshot_policy": { Type: schema.TypeBool, Computed: true, }, "tags": tagsSchema(), }, } setResourceFunc(resource, resourceAlibabacloudStackDiskCreate, resourceAlibabacloudStackDiskRead, resourceAlibabacloudStackDiskUpdate, resourceAlibabacloudStackDiskDelete) return resource } func resourceAlibabacloudStackDiskCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) ecsService := EcsService{client} zoneId := connectivity.GetResourceData(d, "zone_id", "availability_zone").(string) if err := errmsgs.CheckEmpty(zoneId, schema.TypeString, "zone_id", "availability_zone"); err != nil { return errmsgs.WrapError(err) } availabilityZone, err := ecsService.DescribeZone(zoneId) if err != nil { return errmsgs.WrapError(err) } request := ecs.CreateCreateDiskRequest() client.InitRpcRequest(*request.RpcRequest) request.ZoneId = availabilityZone.ZoneId if v, ok := d.GetOk("category"); ok && v.(string) != "" { category := DiskCategory(v.(string)) if err := ecsService.DiskAvailable(availabilityZone, category); err != nil { return errmsgs.WrapError(err) } request.DiskCategory = v.(string) } if v, ok := d.GetOk("size"); ok { request.Size = requests.NewInteger(v.(int)) } if v, ok := d.GetOk("snapshot_id"); ok && v.(string) != "" { request.SnapshotId = v.(string) } if v, ok := connectivity.GetResourceDataOk(d, "disk_name", "name"); ok && v.(string) != "" { request.DiskName = v.(string) } if v, ok := d.GetOk("description"); ok && v.(string) != "" { request.Description = v.(string) } if v, ok := d.GetOk("encrypted"); ok { request.Encrypted = requests.NewBoolean(v.(bool)) if v.(bool) == true { if j, ok4 := d.GetOk("kms_key_id"); ok4 { request.KMSKeyId = j.(string) } if request.KMSKeyId == "" { return errmsgs.WrapError(errors.New("KmsKeyId can not be empty if encrypted is set to \"true\"")) } request.EncryptAlgorithm = d.Get("encrypt_algorithm").(string) } } if v, ok := d.GetOk("tags"); ok && len(v.(map[string]interface{})) > 0 { tags := make([]ecs.CreateDiskTag, len(v.(map[string]interface{}))) for key, value := range v.(map[string]interface{}) { tags = append(tags, ecs.CreateDiskTag{ Key: key, Value: value.(string), }) } request.Tag = &tags } request.ClientToken = buildClientToken(request.GetActionName()) raw, err := client.WithEcsClient(func(ecsClient *ecs.Client) (interface{}, error) { return ecsClient.CreateDisk(request) }) response, ok := raw.(*ecs.CreateDiskResponse) addDebug(request.GetActionName(), raw, request.RpcRequest, request) if err != nil { errmsg := "" if ok { errmsg = errmsgs.GetBaseResponseErrorMessage(response.BaseResponse) } return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, "alibabacloudstack_disk", request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg) } d.SetId(response.DiskId) if err := ecsService.WaitForDisk(d.Id(), Available, DefaultTimeout); err != nil { return errmsgs.WrapError(err) } return nil } func resourceAlibabacloudStackDiskRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) ecsService := EcsService{client} object, err := ecsService.DescribeDisk(d.Id()) if err != nil { if errmsgs.NotFoundError(err) { d.SetId("") return nil } return errmsgs.WrapError(err) } connectivity.SetResourceData(d, object.ZoneId, "zone_id", "availability_zone") d.Set("category", object.Category) d.Set("size", object.Size) d.Set("status", object.Status) connectivity.SetResourceData(d, object.DiskName, "disk_name", "name") d.Set("description", object.Description) d.Set("snapshot_id", object.SourceSnapshotId) d.Set("encrypted", object.Encrypted) d.Set("kms_key_id", object.KMSKeyId) d.Set("delete_auto_snapshot", object.DeleteAutoSnapshot) d.Set("delete_with_instance", object.DeleteWithInstance) d.Set("enable_auto_snapshot", object.EnableAutoSnapshot) d.Set("enable_automated_snapshot_policy", object.EnableAutomatedSnapshotPolicy) d.Set("auto_snapshot_policy_id", object.AutoSnapshotPolicyId) d.Set("tags", ecsService.tagsToMap(object.Tags.Tag)) return nil } func resourceAlibabacloudStackDiskUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) d.Partial(true) update := false request := ecs.CreateModifyDiskAttributeRequest() client.InitRpcRequest(*request.RpcRequest) request.DiskId = d.Id() if !d.IsNewResource() && d.HasChange("disk_name") { request.DiskName = connectivity.GetResourceData(d, "disk_name", "name").(string) update = true //d.SetPartial("disk_name") } if !d.IsNewResource() && d.HasChange("description") { request.Description = d.Get("description").(string) update = true //d.SetPartial("description") } if d.IsNewResource() || d.HasChange("delete_auto_snapshot") { v := d.Get("delete_auto_snapshot") request.DeleteAutoSnapshot = requests.NewBoolean(v.(bool)) update = true //d.SetPartial("delete_auto_snapshot") } if d.IsNewResource() || d.HasChange("delete_with_instance") { v := d.Get("delete_with_instance") request.DeleteWithInstance = requests.NewBoolean(v.(bool)) update = true //d.SetPartial("delete_with_instance") } if d.IsNewResource() || d.HasChange("enable_auto_snapshot") { v := d.Get("enable_auto_snapshot") request.EnableAutoSnapshot = requests.NewBoolean(v.(bool)) update = true //d.SetPartial("enable_auto_snapshot") } if update { raw, err := client.WithEcsClient(func(ecsClient *ecs.Client) (interface{}, error) { return ecsClient.ModifyDiskAttribute(request) }) if err != nil { errmsg := "" if raw != nil { response, ok := raw.(*ecs.ModifyDiskAttributeResponse) if ok { errmsg = errmsgs.GetBaseResponseErrorMessage(response.BaseResponse) } } return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, d.Id(), request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) } if d.IsNewResource() { d.Partial(false) return nil } err := setTags(client, TagResourceDisk, d) if err != nil { return errmsgs.WrapError(err) } //d.SetPartial("tags") if d.HasChange("size") { size := d.Get("size").(int) request := ecs.CreateResizeDiskRequest() client.InitRpcRequest(*request.RpcRequest) request.DiskId = d.Id() request.NewSize = requests.NewInteger(size) request.Type = string(DiskResizeTypeOnline) raw, err := client.WithEcsClient(func(ecsClient *ecs.Client) (interface{}, error) { return ecsClient.ResizeDisk(request) }) if errmsgs.IsExpectedErrors(err, errmsgs.DiskNotSupportOnlineChangeErrors) { request.Type = string(DiskResizeTypeOffline) raw, err = client.WithEcsClient(func(ecsClient *ecs.Client) (interface{}, error) { return ecsClient.ResizeDisk(request) }) } if err != nil { errmsg := "" if raw != nil { response, ok := raw.(*ecs.ResizeDiskResponse) if ok { errmsg = errmsgs.GetBaseResponseErrorMessage(response.BaseResponse) } } return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, d.Id(), request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) //d.SetPartial("size") } d.Partial(false) return nil } func resourceAlibabacloudStackDiskDelete(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) ecsService := EcsService{client} request := ecs.CreateDeleteDiskRequest() client.InitRpcRequest(*request.RpcRequest) request.DiskId = d.Id() err := resource.Retry(5*time.Minute, func() *resource.RetryError { raw, err := client.WithEcsClient(func(ecsClient *ecs.Client) (interface{}, error) { return ecsClient.DeleteDisk(request) }) if err != nil { if errmsgs.IsExpectedErrors(err, errmsgs.DiskInvalidOperation) { return resource.RetryableError(err) } errmsg := "" if raw != nil { response, ok := raw.(*ecs.DeleteDiskResponse) if ok { errmsg = errmsgs.GetBaseResponseErrorMessage(response.BaseResponse) } } return resource.NonRetryableError(errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, d.Id(), request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg)) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) return nil }) if err != nil { return errmsgs.WrapErrorf(err, errmsgs.DefaultErrorMsg, d.Id(), request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR) } return errmsgs.WrapError(ecsService.WaitForDisk(d.Id(), Deleted, DefaultTimeout)) }