From 75bc521f7373ae3438888ba022ed58d436b26a67 Mon Sep 17 00:00:00 2001 From: He Guimin Date: Thu, 4 Jan 2018 08:44:38 +0800 Subject: [PATCH] modify db_instance and output more useful error message --- alicloud/config.go | 14 +- alicloud/diff_suppress_funcs.go | 85 ++++ alicloud/errors.go | 13 + alicloud/import_alicloud_db_instance_test.go | 185 +------ alicloud/provider.go | 35 +- alicloud/resource_alicloud_db_instance.go | 470 ++++++------------ .../resource_alicloud_db_instance_test.go | 428 +--------------- alicloud/resource_alicloud_disk_attachment.go | 19 +- alicloud/resource_alicloud_dns_record.go | 16 +- alicloud/resource_alicloud_eip.go | 4 +- alicloud/resource_alicloud_eip_association.go | 4 +- ...ource_alicloud_ess_scalingconfiguration.go | 4 +- .../resource_alicloud_ess_scalinggroup.go | 1 - alicloud/resource_alicloud_ess_scalingrule.go | 4 +- alicloud/resource_alicloud_ess_schedule.go | 4 +- alicloud/resource_alicloud_instance.go | 237 ++++++--- alicloud/resource_alicloud_instance_test.go | 233 +++++++++ alicloud/resource_alicloud_key_pair.go | 4 +- .../resource_alicloud_key_pair_attachment.go | 4 +- alicloud/resource_alicloud_nat_gateway.go | 6 +- .../resource_alicloud_router_interface.go | 3 +- alicloud/resource_alicloud_security_group.go | 10 +- .../resource_alicloud_security_group_rule.go | 4 +- alicloud/resource_alicloud_slb.go | 117 +++-- alicloud/resource_alicloud_slb_attachment.go | 28 +- alicloud/resource_alicloud_slb_listener.go | 5 +- .../resource_alicloud_slb_listener_test.go | 2 +- alicloud/resource_alicloud_slb_test.go | 9 +- alicloud/resource_alicloud_vpc.go | 6 +- alicloud/resource_alicloud_vroute_entry.go | 6 +- alicloud/resource_alicloud_vswitch.go | 19 +- alicloud/service_alicloud_ess.go | 4 +- alicloud/service_alicloud_rds.go | 198 ++++++-- alicloud/service_alicloud_slb.go | 17 +- alicloud/validators.go | 43 +- alicloud/validators_test.go | 18 - .../denverdino/aliyungo/common/endpoints.xml | 10 + .../denverdino/aliyungo/common/regions.go | 3 +- .../denverdino/aliyungo/common/types.go | 1 + .../denverdino/aliyungo/ecs/instances.go | 69 +++ .../denverdino/aliyungo/ecs/networks.go | 1 + .../denverdino/aliyungo/rds/instances.go | 170 +++++++ .../denverdino/aliyungo/slb/loadbalancers.go | 21 + vendor/vendor.json | 52 +- website/docs/r/db_instance.html.markdown | 106 ++-- 45 files changed, 1395 insertions(+), 1297 deletions(-) diff --git a/alicloud/config.go b/alicloud/config.go index 5f14c34d3cf..99162178efd 100644 --- a/alicloud/config.go +++ b/alicloud/config.go @@ -22,9 +22,10 @@ import ( // Config of aliyun type Config struct { - AccessKey string - SecretKey string - Region common.Region + AccessKey string + SecretKey string + Region common.Region + SecurityToken string } // AliyunClient of aliyun @@ -141,7 +142,7 @@ func (c *Config) validateRegion() error { } func (c *Config) ecsConn() (*ecs.Client, error) { - client := ecs.NewECSClient(c.AccessKey, c.SecretKey, c.Region) + client := ecs.NewECSClientWithSecurityToken(c.AccessKey, c.SecretKey, c.SecurityToken, c.Region) client.SetBusinessInfo(BusinessInfoKey) client.SetUserAgent(getUserAgent()) @@ -167,7 +168,7 @@ func (c *Config) slbConn() (*slb.Client, error) { } func (c *Config) vpcConn() (*ecs.Client, error) { - client := ecs.NewVPCClient(c.AccessKey, c.SecretKey, c.Region) + client := ecs.NewVPCClientWithSecurityToken(c.AccessKey, c.SecretKey, c.SecurityToken, c.Region) client.SetBusinessInfo(BusinessInfoKey) client.SetUserAgent(getUserAgent()) return client, nil @@ -182,6 +183,7 @@ func (c *Config) essConn() (*ess.Client, error) { func (c *Config) ossConn() (*oss.Client, error) { endpointClient := location.NewClient(c.AccessKey, c.SecretKey) + endpointClient.SetSecurityToken(c.SecurityToken) args := &location.DescribeEndpointsArgs{ Id: c.Region, ServiceCode: "oss", @@ -221,7 +223,7 @@ func (c *Config) ramConn() (ram.RamClientInterface, error) { } func (c *Config) csConn() (*cs.Client, error) { - client := cs.NewClient(c.AccessKey, c.SecretKey) + client := cs.NewClientForAussumeRole(c.AccessKey, c.SecretKey, c.SecurityToken) client.SetUserAgent(getUserAgent()) return client, nil } diff --git a/alicloud/diff_suppress_funcs.go b/alicloud/diff_suppress_funcs.go index 827703442f1..ca512fb3595 100644 --- a/alicloud/diff_suppress_funcs.go +++ b/alicloud/diff_suppress_funcs.go @@ -1,9 +1,12 @@ package alicloud import ( + "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/dns" + "github.com/denverdino/aliyungo/rds" "github.com/denverdino/aliyungo/slb" "github.com/hashicorp/terraform/helper/schema" + "strconv" ) func httpHttpsDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { @@ -82,3 +85,85 @@ func dnsPriorityDiffSuppressFunc(k, old, new string, d *schema.ResourceData) boo } return true } + +func slbInternetDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + if internet, ok := d.GetOk("internet"); ok && internet.(bool) { + return true + } + return false +} + +func slbInternetChargeTypeDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + return !slbInternetDiffSuppressFunc(k, old, new, d) +} + +func slbBandwidthDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + if slbInternetDiffSuppressFunc(k, old, new, d) && slb.InternetChargeType(d.Get("internet_charge_type").(string)) == slb.PayByBandwidth { + return false + } + return true +} + +func ecsPrivateIpDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + vswitch := "" + if vsw, ok := d.GetOk("vswitch_id"); ok && vsw.(string) != "" { + vswitch = vsw.(string) + } else if subnet, ok := d.GetOk("subnet_id"); ok && subnet.(string) != "" { + vswitch = subnet.(string) + } + + if vswitch != "" { + return false + } + return true +} +func ecsInternetDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + if allocate, ok := d.GetOk("allocate_public_ip"); ok && allocate.(bool) { + return false + } + return true +} + +func ecsPostPaidDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + if common.InstanceChargeType(d.Get("instance_charge_type").(string)) == common.PrePaid { + return false + } + return true +} + +func ecsChargeTypeSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + if common.InstanceChargeType(old) == common.PrePaid && common.InstanceChargeType(new) == common.PostPaid { + return true + } + return false +} + +func zoneIdDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + if vsw, ok := d.GetOk("vswitch_id"); ok && vsw.(string) != "" { + return true + } else if vsw, ok := d.GetOk("subnet_id"); ok && vsw.(string) != "" { + return true + } else if multi, ok := d.GetOk("multi_az"); ok && multi.(bool) { + return true + } + return false +} + +func logRetentionPeriodDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + if d.Get("log_backup").(bool) { + return false + } + + if v, err := strconv.Atoi(new); err != nil && v > d.Get("retention_period").(int) { + return false + } + + return true +} + +func rdsPostPaidDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool { + if rds.DBPayType(d.Get("instance_charge_type").(string)) == rds.Prepaid { + return false + } + return true +} diff --git a/alicloud/errors.go b/alicloud/errors.go index ddb04b08c21..8fb5f69a7d5 100644 --- a/alicloud/errors.go +++ b/alicloud/errors.go @@ -17,6 +17,8 @@ const ( InstanceLockedForSecurity = "InstanceLockedForSecurity" SystemDiskNotFound = "SystemDiskNotFound" DiskOperationConflict = "OperationConflict" + DiskInternalError = "InternalError" + DiskInvalidOperation = "InvalidOperation.Conflict" // eip EipIncorrectStatus = "IncorrectEipStatus" InstanceIncorrectStatus = "IncorrectInstanceStatus" @@ -28,6 +30,7 @@ const ( ListenerAlreadyExists = "ListenerAlreadyExists" ServiceIsConfiguring = "ServiceIsConfiguring" BackendServerconfiguring = "BackendServer.configuring" + SystemBusy = "SystemBusy" // security_group InvalidInstanceIdAlreadyExists = "InvalidInstanceId.AlreadyExists" InvalidSecurityGroupIdNotFound = "InvalidSecurityGroupId.NotFound" @@ -53,6 +56,16 @@ const ( IncorrectScalingConfigurationLifecycleState = "IncorrectScalingConfigurationLifecycleState" IncorrectScalingGroupStatus = "IncorrectScalingGroupStatus" + // rds + InvalidDBNameNotFound = "InvalidDBName.NotFound" + InvalidDBInstanceNameNotFound = "InvalidDBInstanceName.NotFound" + InvalidCurrentConnectionStringNotFound = "InvalidCurrentConnectionString.NotFound" + NetTypeExists = "NetTypeExists" + InvalidAccountNameDuplicate = "InvalidAccountName.Duplicate" + InvalidAccountNameNotFound = "InvalidAccountName.NotFound" + OperationDeniedDBInstanceStatus = "OperationDenied.DBInstanceStatus" + InvalidConnectionStringDuplicate = "InvalidConnectionString.Duplicate" + AtLeastOneNetTypeExists = "AtLeastOneNetTypeExists" // oss OssBucketNotFound = "NoSuchBucket" OssBodyNotFound = "404 Not Found" diff --git a/alicloud/import_alicloud_db_instance_test.go b/alicloud/import_alicloud_db_instance_test.go index ab5b508e40a..556db56c8c4 100644 --- a/alicloud/import_alicloud_db_instance_test.go +++ b/alicloud/import_alicloud_db_instance_test.go @@ -6,29 +6,7 @@ import ( "github.com/hashicorp/terraform/helper/resource" ) -func TestAccAlicloudDBInstance_importBasic(t *testing.T) { - resourceName := "alicloud_db_instance.foo" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccDBInstanceConfig, - }, - - resource.TestStep{ - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"allocate_public_connection", "period"}, - }, - }, - }) -} - -func TestAccAlicloudDBInstance_importVpc(t *testing.T) { +func TestAccAlicloudDBInstance_import(t *testing.T) { resourceName := "alicloud_db_instance.foo" resource.Test(t, resource.TestCase{ @@ -41,164 +19,9 @@ func TestAccAlicloudDBInstance_importVpc(t *testing.T) { }, resource.TestStep{ - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"allocate_public_connection", "period"}, - }, - }, - }) -} - -func TestAlicloudDBInstance_importPrepaidOrder(t *testing.T) { - resourceName := "alicloud_db_instance.foo" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccDBInstance_prepaid_order, - }, - - resource.TestStep{ - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"allocate_public_connection", "period"}, - }, - }, - }) -} - -func TestAccAlicloudDBInstance_multiIZ(t *testing.T) { - resourceName := "alicloud_db_instance.foo" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccDBInstance_multiAZ, - }, - - resource.TestStep{ - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"allocate_public_connection", "period"}, - }, - }, - }) -} - -func TestAccAlicloudDBInstance_importDatabase(t *testing.T) { - resourceName := "alicloud_db_instance.foo" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccDBInstance_database, - }, - - resource.TestStep{ - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"allocate_public_connection", "period"}, - }, - }, - }) -} - -func TestAccAlicloudDBInstance_importAccount(t *testing.T) { - resourceName := "alicloud_db_instance.foo" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccDBInstance_grantDatabasePrivilege2Account, - }, - - resource.TestStep{ - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"allocate_public_connection", "master_user_password", "period"}, - }, - }, - }) -} - -func TestAccAlicloudDBInstance_importAllocatePublicConnection(t *testing.T) { - resourceName := "alicloud_db_instance.foo" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccDBInstance_allocatePublicConnection, - }, - - resource.TestStep{ - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"allocate_public_connection", "master_user_password", "period"}, - }, - }, - }) -} - -func TestAccAlicloudDBInstance_importBackupPolicy(t *testing.T) { - resourceName := "alicloud_db_instance.foo" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccDBInstance_backup, - }, - - resource.TestStep{ - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"allocate_public_connection", "period"}, - }, - }, - }) -} - -func TestAccAlicloudDBInstance_importSecurityIps(t *testing.T) { - resourceName := "alicloud_db_instance.foo" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccDBInstance_securityIpsConfig, - }, - - resource.TestStep{ - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"allocate_public_connection", "period"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) diff --git a/alicloud/provider.go b/alicloud/provider.go index 9c0ba925d55..426f29dcf14 100644 --- a/alicloud/provider.go +++ b/alicloud/provider.go @@ -15,21 +15,27 @@ func Provider() terraform.ResourceProvider { "access_key": &schema.Schema{ Type: schema.TypeString, Required: true, - DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ACCESS_KEY", nil), + DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ACCESS_KEY", os.Getenv("ALICLOUD_ACCESS_KEY")), Description: descriptions["access_key"], }, "secret_key": &schema.Schema{ Type: schema.TypeString, Required: true, - DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SECRET_KEY", nil), + DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SECRET_KEY", os.Getenv("ALICLOUD_SECRET_KEY")), Description: descriptions["secret_key"], }, "region": &schema.Schema{ Type: schema.TypeString, Required: true, - DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_REGION", DEFAULT_REGION), + DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_REGION", os.Getenv("ALICLOUD_REGION")), Description: descriptions["region"], }, + "security_token": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SECURITY_TOKEN", os.Getenv("SECURITY_TOKEN")), + Description: descriptions["security_token"], + }, }, DataSourcesMap: map[string]*schema.Resource{ @@ -108,25 +114,17 @@ func Provider() terraform.ResourceProvider { } func providerConfigure(d *schema.ResourceData) (interface{}, error) { - accesskey, ok := d.GetOk("access_key") - if !ok { - accesskey = os.Getenv("ALICLOUD_ACCESS_KEY") - } - secretkey, ok := d.GetOk("secret_key") - if !ok { - secretkey = os.Getenv("ALICLOUD_SECRET_KEY") - } region, ok := d.GetOk("region") if !ok { - region = os.Getenv("ALICLOUD_REGION") if region == "" { region = DEFAULT_REGION } } config := Config{ - AccessKey: accesskey.(string), - SecretKey: secretkey.(string), - Region: common.Region(region.(string)), + AccessKey: d.Get("access_key").(string), + SecretKey: d.Get("secret_key").(string), + Region: common.Region(region.(string)), + SecurityToken: d.Get("security_token").(string), } client, err := config.Client() @@ -144,8 +142,9 @@ var descriptions map[string]string func init() { descriptions = map[string]string{ - "access_key": "Access key of alicloud", - "secret_key": "Secret key of alicloud", - "region": "Region of alicloud", + "access_key": "Access key of alicloud", + "secret_key": "Secret key of alicloud", + "region": "Region of alicloud", + "security_token": "Alibaba Cloud Security Token", } } diff --git a/alicloud/resource_alicloud_db_instance.go b/alicloud/resource_alicloud_db_instance.go index 25aa26ea4ef..687c019ce6a 100644 --- a/alicloud/resource_alicloud_db_instance.go +++ b/alicloud/resource_alicloud_db_instance.go @@ -1,12 +1,11 @@ package alicloud import ( - "bytes" "encoding/json" "fmt" "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ecs" "github.com/denverdino/aliyungo/rds" - "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "log" @@ -39,10 +38,21 @@ func resourceAlicloudDBInstance() *schema.Resource { Required: true, }, "db_instance_class": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Deprecated: "Field 'db_instance_class' has been deprecated from provider version 1.5.0. New field 'instance_type' replaces it.", + }, + "instance_type": &schema.Schema{ Type: schema.TypeString, Required: true, }, "db_instance_storage": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Deprecated: "Field 'db_instance_storage' has been deprecated from provider version 1.5.0. New field 'instance_storage' replaces it.", + }, + + "instance_storage": &schema.Schema{ Type: schema.TypeInt, Required: true, }, @@ -54,76 +64,98 @@ func resourceAlicloudDBInstance() *schema.Resource { ForceNew: true, Default: rds.Postpaid, }, + "period": &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validateAllowedIntValue([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 24, 36}), - Optional: true, - ForceNew: true, + Type: schema.TypeInt, + ValidateFunc: validateAllowedIntValue([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 24, 36}), + Optional: true, + Default: 1, + DiffSuppressFunc: rdsPostPaidDiffSuppressFunc, }, "zone_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + DiffSuppressFunc: zoneIdDiffSuppressFunc, + }, + + "multi_az": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"zone_id"}, + }, + + "vswitch_id": &schema.Schema{ Type: schema.TypeString, + ForceNew: true, Optional: true, + }, + + "connection_string": &schema.Schema{ + Type: schema.TypeString, Computed: true, }, - "multi_az": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - ForceNew: true, + + "port": &schema.Schema{ + Type: schema.TypeString, + Computed: true, }, + "db_instance_net_type": &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateAllowedStringValue([]string{string(common.Internet), string(common.Intranet)}), - Optional: true, + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + return true + }, + Deprecated: "Field 'db_instance_net_type' has been deprecated from provider version 1.5.0.", }, "allocate_public_connection": &schema.Schema{ - Type: schema.TypeBool, - Optional: true, - Default: false, + Type: schema.TypeBool, + Optional: true, + Deprecated: "Field 'allocate_public_connection' has been deprecated from provider version 1.5.0. New resource 'alicloud_db_connection' replaces it.", }, "instance_network_type": &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateAllowedStringValue([]string{string(common.VPC), string(common.Classic)}), - Optional: true, - Computed: true, - }, - "vswitch_id": &schema.Schema{ Type: schema.TypeString, - ForceNew: true, Optional: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + return true + }, + Deprecated: "Field 'instance_network_type' has been deprecated from provider version 1.5.0.", }, "master_user_name": &schema.Schema{ - Type: schema.TypeString, - ForceNew: true, - Optional: true, + Type: schema.TypeString, + Optional: true, + Deprecated: "Field 'master_user_name' has been deprecated from provider version 1.5.0. New resource 'alicloud_db_account' field 'name' replaces it.", }, + "master_user_password": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Sensitive: true, + Type: schema.TypeString, + Optional: true, + Deprecated: "Field 'master_user_password' has been deprecated from provider version 1.5.0. New resource 'alicloud_db_account' field 'password' replaces it.", }, "preferred_backup_period": &schema.Schema{ - Type: schema.TypeList, - Elem: &schema.Schema{Type: schema.TypeString}, - // terraform does not support ValidateFunc of TypeList attr - // ValidateFunc: validateAllowedStringValue([]string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}), - Optional: true, - Computed: true, + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Deprecated: "Field 'preferred_backup_period' has been deprecated from provider version 1.5.0. New resource 'alicloud_db_backup_policy' field 'backup_period' replaces it.", }, + "preferred_backup_time": &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validateAllowedStringValue(rds.BACKUP_TIME), - Optional: true, - Computed: true, + Type: schema.TypeString, + Optional: true, + Deprecated: "Field 'preferred_backup_time' has been deprecated from provider version 1.5.0. New resource 'alicloud_db_backup_policy' field 'backup_time' replaces it.", }, + "backup_retention_period": &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validateIntegerInRange(7, 730), - Optional: true, - Computed: true, + Type: schema.TypeInt, + Optional: true, + Deprecated: "Field 'backup_retention_period' has been deprecated from provider version 1.5.0. New resource 'alicloud_db_backup_policy' field 'retention_period' replaces it.", }, "security_ips": &schema.Schema{ @@ -133,11 +165,6 @@ func resourceAlicloudDBInstance() *schema.Resource { Optional: true, }, - "port": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - "connections": &schema.Schema{ Type: schema.TypeList, Elem: &schema.Resource{ @@ -156,7 +183,12 @@ func resourceAlicloudDBInstance() *schema.Resource { }, }, }, + Optional: true, Computed: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + return true + }, + Deprecated: "Field 'connections' has been deprecated from provider version 1.5.0. New resource 'alicloud_db_connection' replaces it.", }, "db_mappings": &schema.Schema{ @@ -179,22 +211,16 @@ func resourceAlicloudDBInstance() *schema.Resource { }, }, Optional: true, - Set: resourceAlicloudDatabaseHash, + Computed: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + return true + }, + Deprecated: "Field 'db_mappings' has been deprecated from provider version 1.5.0. New resource 'alicloud_db_database' replaces it.", }, }, } } -func resourceAlicloudDatabaseHash(v interface{}) int { - var buf bytes.Buffer - m := v.(map[string]interface{}) - buf.WriteString(fmt.Sprintf("%s-", m["db_name"].(string))) - buf.WriteString(fmt.Sprintf("%s-", m["character_set_name"].(string))) - buf.WriteString(fmt.Sprintf("%s-", m["db_description"].(string))) - - return hashcode.String(buf.String()) -} - func resourceAlicloudDBInstanceCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*AliyunClient) conn := client.rdsconn @@ -210,170 +236,62 @@ func resourceAlicloudDBInstanceCreate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Error creating Alicloud db instance: %#v", err) } - instanceId := resp.DBInstanceId - if instanceId == "" { - return fmt.Errorf("Error get Alicloud db instance id") - } - - d.SetId(instanceId) + d.SetId(resp.DBInstanceId) // wait instance status change from Creating to running if err := conn.WaitForInstanceAsyn(d.Id(), rds.Running, defaultLongTimeout); err != nil { return fmt.Errorf("WaitForInstance %s got error: %#v", rds.Running, err) } - if err := modifySecurityIps(d.Id(), d.Get("security_ips"), meta); err != nil { - return err - } - - masterUserName := d.Get("master_user_name").(string) - masterUserPwd := d.Get("master_user_password").(string) - if masterUserName != "" && masterUserPwd != "" { - if err := client.CreateAccountByInfo(d.Id(), masterUserName, masterUserPwd); err != nil { - return fmt.Errorf("Create db account %s error: %v", masterUserName, err) - } - } - - if d.Get("allocate_public_connection").(bool) { - if err := client.AllocateDBPublicConnection(d.Id(), DB_DEFAULT_CONNECT_PORT); err != nil { - return fmt.Errorf("Allocate public connection error: %v", err) - } - } - return resourceAlicloudDBInstanceUpdate(d, meta) } -func modifySecurityIps(id string, ips interface{}, meta interface{}) error { - client := meta.(*AliyunClient) - ipList := expandStringList(ips.([]interface{})) - - ipstr := strings.Join(ipList[:], COMMA_SEPARATED) - // default disable connect from outside - if ipstr == "" { - ipstr = LOCAL_HOST_IP - } - - if err := client.ModifyDBSecurityIps(id, ipstr); err != nil { - return fmt.Errorf("Error modify security ips %s: %#v", ipstr, err) - } - return nil -} - func resourceAlicloudDBInstanceUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*AliyunClient) conn := client.rdsconn d.Partial(true) - if d.HasChange("db_mappings") { - o, n := d.GetChange("db_mappings") - os := o.(*schema.Set) - ns := n.(*schema.Set) - - var allDbs []string - remove := os.Difference(ns).List() - add := ns.Difference(os).List() - - if len(remove) > 0 && len(add) > 0 { - return fmt.Errorf("Failure modify database, we neither support create and delete database simultaneous nor modify database attributes.") - } - - if len(remove) > 0 { - if err := conn.WaitForInstanceAsyn(d.Id(), rds.Running, 600); err != nil { - return fmt.Errorf("WaitForInstance %s got error: %#v", rds.Running, err) - } - for _, db := range remove { - dbm, _ := db.(map[string]interface{}) - if err := conn.DeleteDatabase(d.Id(), dbm["db_name"].(string)); err != nil { - return fmt.Errorf("Failure delete database %s: %#v", dbm["db_name"].(string), err) - } - } - } - - if len(add) > 0 { - if err := conn.WaitForInstanceAsyn(d.Id(), rds.Running, 600); err != nil { - return fmt.Errorf("WaitForInstance %s got error: %#v", rds.Running, err) - } - for _, db := range add { - dbm, _ := db.(map[string]interface{}) - dbName := dbm["db_name"].(string) - allDbs = append(allDbs, dbName) - - if err := client.CreateDatabaseByInfo(d.Id(), dbName, dbm["character_set_name"].(string), dbm["db_description"].(string)); err != nil { - return fmt.Errorf("Failure create database %s: %#v", dbName, err) - } - - } - } + if d.HasChange("security_ips") { + ipList := expandStringList(d.Get("security_ips").([]interface{})) - if err := conn.WaitForAllDatabase(d.Id(), allDbs, rds.Running, 600); err != nil { - return fmt.Errorf("Wait for all databases %s: %#v", rds.Running, err) + ipstr := strings.Join(ipList[:], COMMA_SEPARATED) + // default disable connect from outside + if ipstr == "" { + ipstr = LOCAL_HOST_IP } - if user := d.Get("master_user_name").(string); user != "" { - for _, dbName := range allDbs { - if err := client.GrantDBPrivilege2Account(d.Id(), user, dbName); err != nil { - return fmt.Errorf("Failed to grant database %s readwrite privilege to account %s: %#v", dbName, user, err) - } - } + if err := client.ModifyDBSecurityIps(d.Id(), ipstr); err != nil { + return fmt.Errorf("Moodify DB security ips %s got an error: %#v", ipstr, err) } - - d.SetPartial("db_mappings") + d.SetPartial("security_ips") } - if d.HasChange("preferred_backup_period") || d.HasChange("preferred_backup_time") || d.HasChange("backup_retention_period") { - period := d.Get("preferred_backup_period").([]interface{}) - periodList := expandStringList(period) - time := d.Get("preferred_backup_time").(string) - retention := d.Get("backup_retention_period").(int) - - if time == "" || retention == 0 || len(periodList) < 1 { - return fmt.Errorf("Both backup_time, backup_period and retention_period are required to set backup policy.") - } - - ps := strings.Join(periodList[:], COMMA_SEPARATED) - - if err := client.ConfigDBBackup(d.Id(), time, ps, retention); err != nil { - return fmt.Errorf("Error set backup policy: %#v", err) - } - d.SetPartial("preferred_backup_period") - d.SetPartial("preferred_backup_time") - d.SetPartial("backup_retention_period") + update := false + args := rds.ModifyDBInstanceSpecArgs{ + DBInstanceId: d.Id(), + PayType: rds.Postpaid, } - if d.HasChange("security_ips") { - if err := modifySecurityIps(d.Id(), d.Get("security_ips"), meta); err != nil { - return err - } - d.SetPartial("security_ips") + if d.HasChange("instance_type") && !d.IsNewResource() { + args.DBInstanceClass = d.Get("instance_type").(string) + update = true + d.SetPartial("instance_type") } - if d.HasChange("db_instance_class") || d.HasChange("db_instance_storage") { - co, cn := d.GetChange("db_instance_class") - so, sn := d.GetChange("db_instance_storage") - classOld := co.(string) - classNew := cn.(string) - storageOld := so.(int) - storageNew := sn.(int) - - // update except the first time, because we will do it in create function - if classOld != "" && storageOld != 0 { - chargeType := d.Get("instance_charge_type").(string) - if chargeType == string(rds.Prepaid) { - return fmt.Errorf("Prepaid db instance does not support modify db_instance_class or db_instance_storage") - } - - if err := client.ModifyDBClassStorage(d.Id(), classNew, strconv.Itoa(storageNew)); err != nil { - return fmt.Errorf("Error modify db instance class or storage error: %#v", err) - } - } + if d.HasChange("instance_storage") && !d.IsNewResource() { + args.DBInstanceStorage = strconv.Itoa(d.Get("instance_storage").(int)) + update = true + d.SetPartial("instance_storage") } - if d.HasChange("master_user_password") && !d.IsNewResource() { - d.SetPartial("master_user_password") - if _, err := client.rdsconn.ResetAccountPassword(d.Id(), d.Get("master_user_name").(string), d.Get("master_user_password").(string)); err != nil { - return fmt.Errorf("Error reset db account password error: %#v", err) + if update { + if _, err := conn.ModifyDBInstanceSpec(&args); err != nil { + return err } - + //// wait instance status change from Creating to running + //if err := conn.WaitForInstanceAsyn(d.Id(), rds.Running, defaultLongTimeout); err != nil { + // return fmt.Errorf("WaitForInstance %s got error: %#v", rds.Running, err) + //} } d.Partial(false) @@ -382,42 +300,16 @@ func resourceAlicloudDBInstanceUpdate(d *schema.ResourceData, meta interface{}) func resourceAlicloudDBInstanceRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*AliyunClient) - conn := client.rdsconn instance, err := client.DescribeDBInstanceById(d.Id()) if err != nil { - if NotFoundError(err) { + if NotFoundError(err) || IsExceptedError(err, InvalidDBInstanceNameNotFound) { d.SetId("") return nil } return fmt.Errorf("Error Describe DB InstanceAttribute: %#v", err) } - args := rds.DescribeDatabasesArgs{ - DBInstanceId: d.Id(), - } - - resp, err := conn.DescribeDatabases(&args) - if err != nil { - return err - } - if resp.Databases.Database == nil { - d.SetId("") - return nil - } - - d.Set("db_mappings", flattenDatabaseMappings(resp.Databases.Database)) - - argn := rds.DescribeDBInstanceNetInfoArgs{ - DBInstanceId: d.Id(), - } - - resn, err := conn.DescribeDBInstanceNetInfo(&argn) - if err != nil { - return err - } - d.Set("connections", flattenDBConnections(resn.DBInstanceNetInfos.DBInstanceNetInfo)) - ips, err := client.GetSecurityIps(d.Id(), d.Get("security_ips")) if err != nil { log.Printf("Describe DB security ips error: %#v", err) @@ -426,58 +318,43 @@ func resourceAlicloudDBInstanceRead(d *schema.ResourceData, meta interface{}) er d.Set("engine", instance.Engine) d.Set("engine_version", instance.EngineVersion) - d.Set("db_instance_class", instance.DBInstanceClass) + d.Set("instance_type", instance.DBInstanceClass) d.Set("port", instance.Port) - d.Set("db_instance_storage", instance.DBInstanceStorage) + d.Set("instance_storage", instance.DBInstanceStorage) d.Set("zone_id", instance.ZoneId) - d.Set("db_instance_net_type", instance.DBInstanceNetType) - d.Set("instance_network_type", instance.InstanceNetworkType) d.Set("instance_charge_type", instance.PayType) d.Set("period", d.Get("period")) d.Set("vswitch_id", instance.VSwitchId) - - // Read DB account name - accounts, err := conn.DescribeAccounts(&rds.DescribeAccountsArgs{ - DBInstanceId: d.Id(), - }) - if len(accounts.Accounts.DBInstanceAccount) > 0 { - d.Set("master_user_name", accounts.Accounts.DBInstanceAccount[0].AccountName) - } else { - d.Set("master_user_name", "") - } - - // Read DB backup strategy - backup, err := conn.DescribeBackupPolicy(&rds.DescribeBackupPolicyArgs{ - DBInstanceId: d.Id(), - }) - d.Set("preferred_backup_period", strings.Split(backup.PreferredBackupPeriod, COMMA_SEPARATED)) - d.Set("preferred_backup_time", backup.PreferredBackupTime) - d.Set("backup_retention_period", backup.BackupRetentionPeriod) + d.Set("connection_string", instance.ConnectionString) return nil } func resourceAlicloudDBInstanceDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*AliyunClient).rdsconn + client := meta.(*AliyunClient) return resource.Retry(5*time.Minute, func() *resource.RetryError { - err := conn.DeleteInstance(d.Id()) + err := client.rdsconn.DeleteInstance(d.Id()) if err != nil { - return resource.RetryableError(fmt.Errorf("DB Instance in use - trying again while it is deleted.")) + if NotFoundError(err) || IsExceptedError(err, InvalidDBInstanceNameNotFound) { + return nil + } + return resource.RetryableError(fmt.Errorf("Delete DB instance timeout and got an error: %#v.", err)) } - args := &rds.DescribeDBInstancesArgs{ - DBInstanceId: d.Id(), - } - resp, err := conn.DescribeDBInstanceAttribute(args) + instance, err := client.DescribeDBInstanceById(d.Id()) if err != nil { - return resource.NonRetryableError(err) - } else if len(resp.Items.DBInstanceAttribute) < 1 { + if NotFoundError(err) || IsExceptedError(err, InvalidDBInstanceNameNotFound) { + return nil + } + return resource.NonRetryableError(fmt.Errorf("Error Describe DB InstanceAttribute: %#v", err)) + } + if instance == nil { return nil } - return resource.RetryableError(fmt.Errorf("DB in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete DB instance timeout and got an error: %#v.", err)) }) } @@ -491,10 +368,11 @@ func buildDBCreateOrderArgs(d *schema.ResourceData, meta interface{}) (*rds.Crea AutoPay: "true", EngineVersion: d.Get("engine_version").(string), Engine: rds.Engine(d.Get("engine").(string)), - DBInstanceStorage: d.Get("db_instance_storage").(int), - DBInstanceClass: d.Get("db_instance_class").(string), + DBInstanceStorage: d.Get("instance_storage").(int), + DBInstanceClass: d.Get("instance_type").(string), Quantity: DEFAULT_INSTANCE_COUNT, Resource: rds.DefaultResource, + DBInstanceNetType: common.Intranet, } bussStr, err := json.Marshal(DefaultBusinessInfo) @@ -504,83 +382,63 @@ func buildDBCreateOrderArgs(d *schema.ResourceData, meta interface{}) (*rds.Crea args.BusinessInfo = string(bussStr) - zoneId := d.Get("zone_id").(string) - args.ZoneId = zoneId + if zone, ok := d.GetOk("zone_id"); ok && zone.(string) != "" { + args.ZoneId = zone.(string) + } multiAZ := d.Get("multi_az").(bool) if multiAZ { - if zoneId != "" { - return nil, fmt.Errorf("You cannot set the ZoneId parameter when the MultiAZ parameter is set to true") - } - izs, err := client.DescribeMultiIZByRegion() + azs, err := client.DescribeMultiIZByRegion() if err != nil { - return nil, fmt.Errorf("Get multiAZ id error") + return nil, fmt.Errorf("DescribeMultiIZByRegion got an error: %#v.", err) } - if len(izs) < 1 { - return nil, fmt.Errorf("Current region does not support MultiAZ.") + if len(azs) < 1 { + return nil, fmt.Errorf("Current region does not support multiple availability zones. Please change to other regions.") } - args.ZoneId = izs[0] + args.ZoneId = azs[0] } vswitchId := d.Get("vswitch_id").(string) - networkType := d.Get("instance_network_type").(string) - args.InstanceNetworkType = common.NetworkType(networkType) + args.InstanceNetworkType = common.Classic if vswitchId != "" { args.VSwitchId = vswitchId - - // check InstanceNetworkType with vswitchId - if networkType == string(common.Classic) { - return nil, fmt.Errorf("When fill vswitchId, you shold set instance_network_type to VPC") - } else if networkType == "" { - args.InstanceNetworkType = common.VPC - } - - // get vpcId - vpcId, err := client.GetVpcIdByVSwitchId(vswitchId) - - if err != nil { - return nil, fmt.Errorf("VswitchId %s is not valid of current region", vswitchId) - } - // fill vpcId by vswitchId - args.VPCId = vpcId + args.InstanceNetworkType = common.VPC // check vswitchId in zone - vsw, err := client.QueryVswitchById(vpcId, vswitchId) + vsws, err := client.QueryVswitches(&ecs.DescribeVSwitchesArgs{ + RegionId: getRegion(d, meta), + VSwitchId: vswitchId, + }) if err != nil { - return nil, fmt.Errorf("VswitchId %s is not valid of current region", vswitchId) + return nil, fmt.Errorf("DescribeVSwitches got an error: %#v.", err) } - if zoneId == "" { - args.ZoneId = vsw.ZoneId - } else if vsw.ZoneId != zoneId { - return nil, fmt.Errorf("VswitchId %s is not belong to the zone %s", vswitchId, zoneId) + if len(vsws) < 1 { + return nil, fmt.Errorf("VSwitch %s is not found in the region %s.", vswitchId, getRegion(d, meta)) } - } - if v := d.Get("db_instance_net_type").(string); v != "" { - args.DBInstanceNetType = common.NetType(v) + args.ZoneId = vsws[0].ZoneId + args.VPCId = vsws[0].VpcId } - chargeType := d.Get("instance_charge_type").(string) - if chargeType != "" { - args.PayType = rds.DBPayType(chargeType) - } else { - args.PayType = rds.Postpaid - } + args.PayType = rds.DBPayType(d.Get("instance_charge_type").(string)) // if charge type is postpaid, the commodity code must set to bards - if chargeType == string(rds.Postpaid) { + args.CommodityCode = rds.Rds + if args.PayType == rds.Postpaid { args.CommodityCode = rds.Bards - } else { - args.CommodityCode = rds.Rds - } - period := d.Get("period").(int) - args.UsedTime, args.TimeType = TransformPeriod2Time(period, chargeType) + period := d.Get("period").(int) + args.UsedTime = period + args.TimeType = common.Month + if period > 9 { + args.TimeType = common.Year + } + } return args, nil } diff --git a/alicloud/resource_alicloud_db_instance_test.go b/alicloud/resource_alicloud_db_instance_test.go index 90484305c4b..9fd285df786 100644 --- a/alicloud/resource_alicloud_db_instance_test.go +++ b/alicloud/resource_alicloud_db_instance_test.go @@ -31,20 +31,8 @@ func TestAccAlicloudDBInstance_basic(t *testing.T) { "alicloud_db_instance.foo", &instance), resource.TestCheckResourceAttr( "alicloud_db_instance.foo", - "port", - "3306"), - resource.TestCheckResourceAttr( - "alicloud_db_instance.foo", - "db_instance_storage", + "instance_storage", "10"), - resource.TestCheckResourceAttr( - "alicloud_db_instance.foo", - "instance_network_type", - "Classic"), - resource.TestCheckResourceAttr( - "alicloud_db_instance.foo", - "db_instance_net_type", - "Intranet"), resource.TestCheckResourceAttr( "alicloud_db_instance.foo", "engine_version", @@ -81,70 +69,8 @@ func TestAccAlicloudDBInstance_vpc(t *testing.T) { "alicloud_db_instance.foo", &instance), resource.TestCheckResourceAttr( "alicloud_db_instance.foo", - "port", - "3306"), - resource.TestCheckResourceAttr( - "alicloud_db_instance.foo", - "db_instance_storage", + "instance_storage", "10"), - resource.TestCheckResourceAttr( - "alicloud_db_instance.foo", - "instance_network_type", - "VPC"), - resource.TestCheckResourceAttr( - "alicloud_db_instance.foo", - "db_instance_net_type", - "Intranet"), - resource.TestCheckResourceAttr( - "alicloud_db_instance.foo", - "engine_version", - "5.6"), - resource.TestCheckResourceAttr( - "alicloud_db_instance.foo", - "engine", - "MySQL"), - ), - }, - }, - }) - -} - -func TestC2CAlicloudDBInstance_prepaid_order(t *testing.T) { - var instance rds.DBInstanceAttribute - - resource.Test(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - }, - - // module name - IDRefreshName: "alicloud_db_instance.foo", - - Providers: testAccProviders, - CheckDestroy: testAccCheckDBInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccDBInstance_prepaid_order, - Check: resource.ComposeTestCheckFunc( - testAccCheckDBInstanceExists( - "alicloud_db_instance.foo", &instance), - resource.TestCheckResourceAttr( - "alicloud_db_instance.foo", - "port", - "3306"), - resource.TestCheckResourceAttr( - "alicloud_db_instance.foo", - "db_instance_storage", - "10"), - resource.TestCheckResourceAttr( - "alicloud_db_instance.foo", - "instance_network_type", - "VPC"), - resource.TestCheckResourceAttr( - "alicloud_db_instance.foo", - "db_instance_net_type", - "Intranet"), resource.TestCheckResourceAttr( "alicloud_db_instance.foo", "engine_version", @@ -187,126 +113,6 @@ func TestAccAlicloudDBInstance_multiAZ(t *testing.T) { } -func TestAccAlicloudDBInstance_database(t *testing.T) { - var instance rds.DBInstanceAttribute - - resource.Test(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - }, - - // module name - IDRefreshName: "alicloud_db_instance.foo", - - Providers: testAccProviders, - CheckDestroy: testAccCheckDBInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccDBInstance_database, - Check: resource.ComposeTestCheckFunc( - testAccCheckDBInstanceExists( - "alicloud_db_instance.foo", &instance), - resource.TestCheckResourceAttr("alicloud_db_instance.foo", "db_mappings.#", "2"), - ), - }, - - resource.TestStep{ - Config: testAccDBInstance_database_update, - Check: resource.ComposeTestCheckFunc( - testAccCheckDBInstanceExists( - "alicloud_db_instance.foo", &instance), - resource.TestCheckResourceAttr("alicloud_db_instance.foo", "db_mappings.#", "3"), - ), - }, - }, - }) - -} - -func TestAccAlicloudDBInstance_account(t *testing.T) { - var instance rds.DBInstanceAttribute - - resource.Test(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - }, - - // module name - IDRefreshName: "alicloud_db_instance.foo", - - Providers: testAccProviders, - CheckDestroy: testAccCheckDBInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccDBInstance_grantDatabasePrivilege2Account, - Check: resource.ComposeTestCheckFunc( - testAccCheckDBInstanceExists( - "alicloud_db_instance.foo", &instance), - resource.TestCheckResourceAttr("alicloud_db_instance.foo", "db_mappings.#", "2"), - testAccCheckAccountHasPrivilege2Database("alicloud_db_instance.foo", "tester", "foo", "ReadWrite"), - ), - }, - }, - }) - -} - -func TestAccAlicloudDBInstance_allocatePublicConnection(t *testing.T) { - var instance rds.DBInstanceAttribute - - resource.Test(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - }, - - // module name - IDRefreshName: "alicloud_db_instance.foo", - - Providers: testAccProviders, - CheckDestroy: testAccCheckDBInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccDBInstance_allocatePublicConnection, - Check: resource.ComposeTestCheckFunc( - testAccCheckDBInstanceExists( - "alicloud_db_instance.foo", &instance), - resource.TestCheckResourceAttr("alicloud_db_instance.foo", "connections.#", "2"), - testAccCheckHasPublicConnection("alicloud_db_instance.foo"), - ), - }, - }, - }) - -} - -func TestAccAlicloudDBInstance_backupPolicy(t *testing.T) { - var policies []map[string]interface{} - - resource.Test(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheck(t) - }, - - // module name - IDRefreshName: "alicloud_db_instance.foo", - - Providers: testAccProviders, - CheckDestroy: testAccCheckDBInstanceDestroy, - Steps: []resource.TestStep{ - resource.TestStep{ - Config: testAccDBInstance_backup, - Check: resource.ComposeTestCheckFunc( - testAccCheckBackupPolicyExists( - "alicloud_db_instance.foo", policies), - testAccCheckKeyValueInMaps(policies, "backup policy", "preferred_backup_period", "Wednesday,Thursday"), - testAccCheckKeyValueInMaps(policies, "backup policy", "preferred_backup_time", "00:00Z-01:00Z"), - ), - }, - }, - }) - -} - func TestAccAlicloudDBInstance_securityIps(t *testing.T) { var ips []map[string]interface{} @@ -331,7 +137,7 @@ func TestAccAlicloudDBInstance_securityIps(t *testing.T) { }, resource.TestStep{ - Config: testAccDBInstance_securityIpsConfig, + Config: testAccDBInstance_securityIpsUpdate, Check: resource.ComposeTestCheckFunc( testAccCheckSecurityIpExists( "alicloud_db_instance.foo", ips), @@ -362,7 +168,7 @@ func TestAccAlicloudDBInstance_upgradeClass(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckDBInstanceExists( "alicloud_db_instance.foo", &instance), - resource.TestCheckResourceAttr("alicloud_db_instance.foo", "db_instance_class", "rds.mysql.t1.small"), + resource.TestCheckResourceAttr("alicloud_db_instance.foo", "instance_type", "rds.mysql.t1.small"), ), }, @@ -371,7 +177,7 @@ func TestAccAlicloudDBInstance_upgradeClass(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckDBInstanceExists( "alicloud_db_instance.foo", &instance), - resource.TestCheckResourceAttr("alicloud_db_instance.foo", "db_instance_class", "rds.mysql.s1.small"), + resource.TestCheckResourceAttr("alicloud_db_instance.foo", "instance_type", "rds.mysql.s1.small"), ), }, }, @@ -422,44 +228,6 @@ func testAccCheckDBInstanceMultiIZ(i *rds.DBInstanceAttribute) resource.TestChec } } -func testAccCheckAccountHasPrivilege2Database(n, accountName, dbName, privilege 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 fmt.Errorf("No DB instance ID is set") - } - - conn := testAccProvider.Meta().(*AliyunClient).rdsconn - if err := conn.WaitForAccountPrivilege(rs.Primary.ID, accountName, dbName, rds.AccountPrivilege(privilege), 50); err != nil { - return fmt.Errorf("Failed to grant database %s privilege to account %s: %v", dbName, accountName, err) - } - return nil - } -} - -func testAccCheckHasPublicConnection(n 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 fmt.Errorf("No DB instance ID is set") - } - - conn := testAccProvider.Meta().(*AliyunClient).rdsconn - if err := conn.WaitForPublicConnection(rs.Primary.ID, 50); err != nil { - return fmt.Errorf("Failed to allocate public connection: %v", err) - } - return nil - } -} - func testAccCheckDBInstanceExists(n string, d *rds.DBInstanceAttribute) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -488,37 +256,6 @@ func testAccCheckDBInstanceExists(n string, d *rds.DBInstanceAttribute) resource } } -func testAccCheckBackupPolicyExists(n string, ps []map[string]interface{}) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Backup policy not found: %s", n) - } - - if rs.Primary.ID == "" { - return fmt.Errorf("No DB Instance ID is set") - } - - conn := testAccProvider.Meta().(*AliyunClient).rdsconn - - args := rds.DescribeBackupPolicyArgs{ - DBInstanceId: rs.Primary.ID, - } - resp, err := conn.DescribeBackupPolicy(&args) - log.Printf("[DEBUG] check instance %s backup policy %#v", rs.Primary.ID, resp) - - if err != nil { - return err - } - - var bs []rds.BackupPolicy - bs = append(bs, resp.BackupPolicy) - ps = flattenDBBackup(bs) - - return nil - } -} - func testAccCheckKeyValueInMaps(ps []map[string]interface{}, propName, key, value string) resource.TestCheckFunc { return func(s *terraform.State) error { for _, policy := range ps { @@ -546,8 +283,7 @@ func testAccCheckDBInstanceDestroy(s *terraform.State) error { // Verify the error is what we want if err != nil { - // Verify the error is what we want - if NotFoundError(err) { + if NotFoundError(err) || IsExceptedError(err, InvalidDBInstanceNameNotFound) { continue } return err @@ -561,10 +297,9 @@ const testAccDBInstanceConfig = ` resource "alicloud_db_instance" "foo" { engine = "MySQL" engine_version = "5.6" - db_instance_class = "rds.mysql.t1.small" - db_instance_storage = "10" + instance_type = "rds.mysql.t1.small" + instance_storage = "10" instance_charge_type = "Postpaid" - db_instance_net_type = "Intranet" } ` @@ -587,157 +322,40 @@ resource "alicloud_vswitch" "foo" { resource "alicloud_db_instance" "foo" { engine = "MySQL" engine_version = "5.6" - db_instance_class = "rds.mysql.t1.small" - db_instance_storage = "10" + instance_type = "rds.mysql.t1.small" + instance_storage = "10" instance_charge_type = "Postpaid" - db_instance_net_type = "Intranet" vswitch_id = "${alicloud_vswitch.foo.id}" + security_ips = ["10.168.1.12", "100.69.7.112"] } ` const testAccDBInstance_multiAZ = ` resource "alicloud_db_instance" "foo" { engine = "MySQL" engine_version = "5.6" - db_instance_class = "rds.mysql.t1.small" - db_instance_storage = "10" - db_instance_net_type = "Intranet" + instance_type = "rds.mysql.t1.small" + instance_storage = "10" multi_az = true } ` -const testAccDBInstance_prepaid_order = ` -resource "alicloud_db_instance" "foo" { - engine = "MySQL" - engine_version = "5.6" - db_instance_class = "rds.mysql.t1.small" - db_instance_storage = "10" - instance_charge_type = "Prepaid" - db_instance_net_type = "Intranet" -} -` - -const testAccDBInstance_database = ` -resource "alicloud_db_instance" "foo" { - engine = "MySQL" - engine_version = "5.6" - db_instance_class = "rds.mysql.t1.small" - db_instance_storage = "10" - instance_charge_type = "Postpaid" - db_instance_net_type = "Intranet" - - db_mappings = [ - { - "db_name" = "foo" - "character_set_name" = "utf8" - "db_description" = "tf" - },{ - "db_name" = "bar" - "character_set_name" = "utf8" - "db_description" = "tf" - }] -} -` -const testAccDBInstance_database_update = ` -resource "alicloud_db_instance" "foo" { - engine = "MySQL" - engine_version = "5.6" - db_instance_class = "rds.mysql.t1.small" - db_instance_storage = "10" - instance_charge_type = "Postpaid" - db_instance_net_type = "Intranet" - - db_mappings = [ - { - "db_name" = "foo" - "character_set_name" = "utf8" - "db_description" = "tf" - },{ - "db_name" = "bar" - "character_set_name" = "utf8" - "db_description" = "tf" - },{ - "db_name" = "zzz" - "character_set_name" = "utf8" - "db_description" = "tf" - }] -} -` - -const testAccDBInstance_grantDatabasePrivilege2Account = ` -resource "alicloud_db_instance" "foo" { - engine = "MySQL" - engine_version = "5.6" - db_instance_class = "rds.mysql.t1.small" - db_instance_storage = "10" - instance_charge_type = "Postpaid" - db_instance_net_type = "Intranet" - - master_user_name = "tester" - master_user_password = "Test12345" - - db_mappings = [ - { - "db_name" = "foo" - "character_set_name" = "utf8" - "db_description" = "tf" - },{ - "db_name" = "bar" - "character_set_name" = "utf8" - "db_description" = "tf" - }] -} -` - -const testAccDBInstance_allocatePublicConnection = ` -resource "alicloud_db_instance" "foo" { - engine = "MySQL" - engine_version = "5.6" - db_instance_class = "rds.mysql.t1.small" - db_instance_storage = "10" - instance_charge_type = "Postpaid" - db_instance_net_type = "Intranet" - - master_user_name = "tester" - master_user_password = "Test12345" - - allocate_public_connection = true -} -` - -const testAccDBInstance_backup = ` -resource "alicloud_db_instance" "foo" { - engine = "MySQL" - engine_version = "5.6" - db_instance_class = "rds.mysql.t1.small" - db_instance_storage = "10" - instance_charge_type = "Postpaid" - db_instance_net_type = "Intranet" - - preferred_backup_period = ["Wednesday","Thursday"] - preferred_backup_time = "00:00Z-01:00Z" - backup_retention_period = 9 -} -` - const testAccDBInstance_securityIps = ` resource "alicloud_db_instance" "foo" { engine = "MySQL" engine_version = "5.6" - db_instance_class = "rds.mysql.t1.small" - db_instance_storage = "10" + instance_type = "rds.mysql.t1.small" + instance_storage = "10" instance_charge_type = "Postpaid" - db_instance_net_type = "Intranet" } ` -const testAccDBInstance_securityIpsConfig = ` +const testAccDBInstance_securityIpsUpdate = ` resource "alicloud_db_instance" "foo" { engine = "MySQL" engine_version = "5.6" - db_instance_class = "rds.mysql.t1.small" - db_instance_storage = "10" + instance_type = "rds.mysql.t1.small" + instance_storage = "10" instance_charge_type = "Postpaid" - db_instance_net_type = "Intranet" security_ips = ["10.168.1.12", "100.69.7.112"] } @@ -747,17 +365,15 @@ const testAccDBInstance_class = ` resource "alicloud_db_instance" "foo" { engine = "MySQL" engine_version = "5.6" - db_instance_class = "rds.mysql.t1.small" - db_instance_storage = "10" - db_instance_net_type = "Intranet" + instance_type = "rds.mysql.t1.small" + instance_storage = "10" } ` const testAccDBInstance_classUpgrade = ` resource "alicloud_db_instance" "foo" { engine = "MySQL" engine_version = "5.6" - db_instance_class = "rds.mysql.s1.small" - db_instance_storage = "10" - db_instance_net_type = "Intranet" + instance_type = "rds.mysql.s1.small" + instance_storage = "10" } ` diff --git a/alicloud/resource_alicloud_disk_attachment.go b/alicloud/resource_alicloud_disk_attachment.go index adac0814cf3..8c5da06e11b 100644 --- a/alicloud/resource_alicloud_disk_attachment.go +++ b/alicloud/resource_alicloud_disk_attachment.go @@ -4,7 +4,6 @@ import ( "fmt" "strings" - "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/ecs" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" @@ -97,9 +96,9 @@ func resourceAliyunDiskAttachmentDelete(d *schema.ResourceData, meta interface{} return resource.Retry(5*time.Minute, func() *resource.RetryError { err := conn.DetachDisk(instanceID, diskID) if err != nil { - e, _ := err.(*common.Error) - if e.ErrorResponse.Code == DiskIncorrectStatus || e.ErrorResponse.Code == InstanceLockedForSecurity { - return resource.RetryableError(fmt.Errorf("Disk in use - trying again while it detaches")) + if IsExceptedError(err, DiskIncorrectStatus) || IsExceptedError(err, InstanceLockedForSecurity) || + IsExceptedError(err, DiskInvalidOperation) { + return resource.RetryableError(fmt.Errorf("Detach Disk timeout and got an error: %#v", err)) } } @@ -115,7 +114,7 @@ func resourceAliyunDiskAttachmentDelete(d *schema.ResourceData, meta interface{} for _, disk := range disks { if disk.Status != ecs.DiskStatusAvailable { - return resource.RetryableError(fmt.Errorf("Disk in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Detach Disk timeout and got an error: %#v", err)) } } return nil @@ -146,10 +145,10 @@ func diskAttachment(d *schema.ResourceData, meta interface{}) error { log.Printf("error : %s", err) if err != nil { - e, _ := err.(*common.Error) - if e.ErrorResponse.Code == DiskIncorrectStatus || e.ErrorResponse.Code == InstanceIncorrectStatus || - e.ErrorResponse.Code == DiskOperationConflict { - return resource.RetryableError(fmt.Errorf("Disk or Instance status is incorrect - trying again while it attaches")) + if IsExceptedError(err, DiskIncorrectStatus) || IsExceptedError(err, InstanceIncorrectStatus) || + IsExceptedError(err, DiskOperationConflict) || IsExceptedError(err, DiskInternalError) || + IsExceptedError(err, DiskInvalidOperation) { + return resource.RetryableError(fmt.Errorf("Attach Disk timeout and got an error: %#v", err)) } return resource.NonRetryableError(err) } @@ -166,7 +165,7 @@ func diskAttachment(d *schema.ResourceData, meta interface{}) error { } if disks == nil || len(disks) <= 0 { - return resource.RetryableError(fmt.Errorf("Disk in attaching - trying again while it is attached.")) + return resource.RetryableError(fmt.Errorf("Attach Disk timeout and got an error: %#v", err)) } return nil diff --git a/alicloud/resource_alicloud_dns_record.go b/alicloud/resource_alicloud_dns_record.go index 148cc2b3fc3..5334891c48d 100644 --- a/alicloud/resource_alicloud_dns_record.go +++ b/alicloud/resource_alicloud_dns_record.go @@ -161,7 +161,6 @@ func resourceAlicloudDnsRecordRead(d *schema.ResourceData, meta interface{}) err } record := response.RecordTypeNew - //priority, _ := record.Priority d.Set("ttl", record.TTL) d.Set("priority", record.Priority) d.Set("name", record.DomainName) @@ -189,6 +188,21 @@ func resourceAlicloudDnsRecordDelete(d *schema.ResourceData, meta interface{}) e } return resource.NonRetryableError(fmt.Errorf("Error deleting domain record %s: %#v", d.Id(), err)) } + + response, err := conn.DescribeDomainRecordInfoNew(&dns.DescribeDomainRecordInfoNewArgs{ + RecordId: d.Id(), + }) + if err != nil { + if NotFoundError(err) { + return nil + } + return resource.NonRetryableError(fmt.Errorf("Describe domain record got an error: %#v.", err)) + } + + if response == nil { + return nil + } + return nil }) } diff --git a/alicloud/resource_alicloud_eip.go b/alicloud/resource_alicloud_eip.go index 482c4593308..2f68120c6b5 100644 --- a/alicloud/resource_alicloud_eip.go +++ b/alicloud/resource_alicloud_eip.go @@ -134,7 +134,7 @@ func resourceAliyunEipDelete(d *schema.ResourceData, meta interface{}) error { if err != nil { e, _ := err.(*common.Error) if e.ErrorResponse.Code == EipIncorrectStatus { - return resource.RetryableError(fmt.Errorf("EIP in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete EIP timeout and got an error:%#v.", err)) } } @@ -149,7 +149,7 @@ func resourceAliyunEipDelete(d *schema.ResourceData, meta interface{}) error { } else if eips == nil || len(eips) < 1 { return nil } - return resource.RetryableError(fmt.Errorf("EIP in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete EIP timeout and got an error:%#v.", err)) }) } diff --git a/alicloud/resource_alicloud_eip_association.go b/alicloud/resource_alicloud_eip_association.go index 60b0c969839..58be6c5f66e 100644 --- a/alicloud/resource_alicloud_eip_association.go +++ b/alicloud/resource_alicloud_eip_association.go @@ -99,7 +99,7 @@ func resourceAliyunEipAssociationDelete(d *schema.ResourceData, meta interface{} e, _ := err.(*common.Error) errCode := e.ErrorResponse.Code if errCode == InstanceIncorrectStatus || errCode == HaVipIncorrectStatus { - return resource.RetryableError(fmt.Errorf("Eip in use - trying again while make it unassociated.")) + return resource.RetryableError(fmt.Errorf("Unassociat EIP timeout and got an error:%#v.", err)) } } @@ -117,7 +117,7 @@ func resourceAliyunEipAssociationDelete(d *schema.ResourceData, meta interface{} } for _, eip := range eips { if eip.Status != ecs.EipStatusAvailable { - return resource.RetryableError(fmt.Errorf("Eip in use - trying again while make it unassociated.")) + return resource.RetryableError(fmt.Errorf("Unassociat EIP timeout and got an error:%#v.", err)) } } diff --git a/alicloud/resource_alicloud_ess_scalingconfiguration.go b/alicloud/resource_alicloud_ess_scalingconfiguration.go index d60bd974198..f15c4c8d4fd 100644 --- a/alicloud/resource_alicloud_ess_scalingconfiguration.go +++ b/alicloud/resource_alicloud_ess_scalingconfiguration.go @@ -379,7 +379,7 @@ func resourceAliyunEssScalingConfigurationDelete(d *schema.ResourceData, meta in } if e.ErrorResponse.Code != InvalidScalingGroupIdNotFound { return resource.RetryableError( - fmt.Errorf("Scaling configuration in use - trying again while it is deleted.")) + fmt.Errorf("Delete scaling configuration timeout and got an error:%#v.", err)) } } @@ -404,7 +404,7 @@ func resourceAliyunEssScalingConfigurationDelete(d *schema.ResourceData, meta in } return resource.RetryableError( - fmt.Errorf("Scaling configuration in use - trying again while it is deleted.")) + fmt.Errorf("Delete scaling configuration timeout and got an error:%#v.", err)) }) } diff --git a/alicloud/resource_alicloud_ess_scalinggroup.go b/alicloud/resource_alicloud_ess_scalinggroup.go index fc5d71887e5..8898970a4f5 100644 --- a/alicloud/resource_alicloud_ess_scalinggroup.go +++ b/alicloud/resource_alicloud_ess_scalinggroup.go @@ -195,7 +195,6 @@ func buildAlicloudEssScalingGroupArgs(d *schema.ResourceData, meta interface{}) lbs, ok := d.GetOk("loadbalancer_ids") if ok { - //lbsStrings := lbs.([]interface{}) args.LoadBalancerIds = convertListToJsonString(lbs.([]interface{})) } diff --git a/alicloud/resource_alicloud_ess_scalingrule.go b/alicloud/resource_alicloud_ess_scalingrule.go index 135b193f828..18e76870986 100644 --- a/alicloud/resource_alicloud_ess_scalingrule.go +++ b/alicloud/resource_alicloud_ess_scalingrule.go @@ -100,7 +100,7 @@ func resourceAliyunEssScalingRuleDelete(d *schema.ResourceData, meta interface{} err := client.DeleteScalingRuleById(ids[1]) if err != nil { - return resource.RetryableError(fmt.Errorf("Scaling rule in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete scaling rule timeout and got an error:%#v.", err)) } _, err = client.DescribeScalingRuleById(ids[0], ids[1]) @@ -111,7 +111,7 @@ func resourceAliyunEssScalingRuleDelete(d *schema.ResourceData, meta interface{} return resource.NonRetryableError(err) } - return resource.RetryableError(fmt.Errorf("Scaling rule in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete scaling rule timeout and got an error:%#v.", err)) }) } diff --git a/alicloud/resource_alicloud_ess_schedule.go b/alicloud/resource_alicloud_ess_schedule.go index 3755bef02e4..f6006b06900 100644 --- a/alicloud/resource_alicloud_ess_schedule.go +++ b/alicloud/resource_alicloud_ess_schedule.go @@ -171,7 +171,7 @@ func resourceAliyunEssScheduleDelete(d *schema.ResourceData, meta interface{}) e err := client.DeleteScheduleById(d.Id()) if err != nil { - return resource.RetryableError(fmt.Errorf("Scaling schedule in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete scaling schedule timeout and got an error:%#v.", err)) } _, err = client.DescribeScheduleById(d.Id()) @@ -182,7 +182,7 @@ func resourceAliyunEssScheduleDelete(d *schema.ResourceData, meta interface{}) e return resource.NonRetryableError(err) } - return resource.RetryableError(fmt.Errorf("Scaling schedule in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete scaling schedule timeout and got an error:%#v.", err)) }) } diff --git a/alicloud/resource_alicloud_instance.go b/alicloud/resource_alicloud_instance.go index e517ad916c4..f6406efe42f 100644 --- a/alicloud/resource_alicloud_instance.go +++ b/alicloud/resource_alicloud_instance.go @@ -24,10 +24,10 @@ func resourceAliyunInstance() *schema.Resource { Schema: map[string]*schema.Schema{ "availability_zone": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Computed: true, + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: zoneIdDiffSuppressFunc, }, "image_id": &schema.Schema{ @@ -68,22 +68,25 @@ func resourceAliyunInstance() *schema.Resource { }, "internet_charge_type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Computed: true, - ValidateFunc: validateInternetChargeType, + Type: schema.TypeString, + Optional: true, + //ForceNew: true, + Computed: true, + ValidateFunc: validateInternetChargeType, + DiffSuppressFunc: ecsInternetDiffSuppressFunc, }, "internet_max_bandwidth_in": &schema.Schema{ Type: schema.TypeString, Optional: true, - ForceNew: true, + //ForceNew: true, + DiffSuppressFunc: ecsInternetDiffSuppressFunc, }, "internet_max_bandwidth_out": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - ForceNew: true, - ValidateFunc: validateInternetMaxBandWidthOut, + Type: schema.TypeInt, + Optional: true, + //ForceNew: true, + ValidateFunc: validateIntegerInRange(0, 100), + DiffSuppressFunc: ecsInternetDiffSuppressFunc, }, "host_name": &schema.Schema{ Type: schema.TypeString, @@ -120,38 +123,59 @@ func resourceAliyunInstance() *schema.Resource { //subnet_id and vswitch_id both exists, cause compatible old version, and aws habit. "subnet_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Computed: true, //add this schema cause subnet_id not used enter parameter, will different, so will be ForceNew + Type: schema.TypeString, + Optional: true, + Computed: true, //add this schema cause subnet_id not used enter parameter, will different, so will be ForceNew + ConflictsWith: []string{"vswitch_id"}, }, "vswitch_id": &schema.Schema{ Type: schema.TypeString, Optional: true, - ForceNew: true, + }, + + "private_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + DiffSuppressFunc: ecsPrivateIpDiffSuppressFunc, }, "instance_charge_type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ValidateFunc: validateInstanceChargeType, - Default: common.PostPaid, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateInstanceChargeType, + Default: common.PostPaid, + DiffSuppressFunc: ecsChargeTypeSuppressFunc, }, "period": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - ForceNew: true, + Type: schema.TypeInt, + Optional: true, + Default: 1, + ValidateFunc: validateInstanceChargeTypePeriod, + DiffSuppressFunc: ecsPostPaidDiffSuppressFunc, }, - - "public_ip": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, + "period_unit": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: common.Month, + ValidateFunc: validateInstanceChargeTypePeriodUnit, + DiffSuppressFunc: ecsPostPaidDiffSuppressFunc, + }, + "include_data_disks": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + DiffSuppressFunc: ecsPostPaidDiffSuppressFunc, + }, + "dry_run": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + DiffSuppressFunc: ecsPostPaidDiffSuppressFunc, }, - "private_ip": &schema.Schema{ + "public_ip": &schema.Schema{ Type: schema.TypeString, Computed: true, }, @@ -454,32 +478,6 @@ func resourceAliyunInstanceUpdate(d *schema.ResourceData, meta interface{}) erro } } - if imageUpdate || passwordUpdate { - instance, errDesc := conn.DescribeInstanceAttribute(d.Id()) - if errDesc != nil { - return fmt.Errorf("Describe instance got an error: %#v", errDesc) - } - if instance.Status != ecs.Running && instance.Status != ecs.Stopped { - return fmt.Errorf("ECS instance's status doesn't support to start or reboot operation after replace image_id or update password. The current instance's status is %#v", instance.Status) - } else if instance.Status == ecs.Running { - log.Printf("[DEBUG] Reboot instance after change image or password") - if err := conn.RebootInstance(d.Id(), false); err != nil { - return fmt.Errorf("RebootInstance got error: %#v", err) - } - } else { - log.Printf("[DEBUG] Start instance after change image or password") - if err := conn.StartInstance(d.Id()); err != nil { - return fmt.Errorf("StartInstance got error: %#v", err) - } - } - - // Start instance sometimes costs more than 8 minutes when os type is centos. - if err := conn.WaitForInstance(d.Id(), ecs.Running, 500); err != nil { - return fmt.Errorf("WaitForInstance got error: %#v", err) - } - - } - if d.HasChange("security_groups") { o, n := d.GetChange("security_groups") os := o.(*schema.Set) @@ -504,6 +502,78 @@ func resourceAliyunInstanceUpdate(d *schema.ResourceData, meta interface{}) erro d.SetPartial("security_groups") } + vpcUpdate := false + vpcArgs := &ecs.ModifyInstanceVpcAttributeArgs{ + InstanceId: d.Id(), + VSwitchId: d.Get("vswitch_id").(string), + } + + if d.HasChange("vswitch_id") && !d.IsNewResource() { + if d.Get("vswitch_id").(string) == "" { + return fmt.Errorf("Field 'vswitch_id' is required when modifying the instance VPC attribute.") + } + vpcUpdate = true + d.SetPartial("vswitch_id") + } + + if d.HasChange("subnet_id") && !d.IsNewResource() { + if d.Get("subnet_id").(string) == "" { + return fmt.Errorf("Field 'subnet_id' is required when modifying the instance VPC attribute.") + } + vpcArgs.VSwitchId = d.Get("subnet_id").(string) + vpcUpdate = true + d.SetPartial("subnet_id") + } + + if vpcArgs.VSwitchId != "" && d.HasChange("private_ip") && !d.IsNewResource() { + vpcArgs.PrivateIpAddress = d.Get("private_ip").(string) + vpcUpdate = true + d.SetPartial("private_ip") + } + + if imageUpdate || passwordUpdate || vpcUpdate { + instance, errDesc := conn.DescribeInstanceAttribute(d.Id()) + if errDesc != nil { + return fmt.Errorf("Describe instance got an error: %#v", errDesc) + } + if instance.Status == ecs.Running { + log.Printf("[DEBUG] Stop instance when changing image or password or vpc attribute") + if err := conn.StopInstance(d.Id(), false); err != nil { + return fmt.Errorf("StopInstance got error: %#v", err) + } + if err := conn.WaitForInstanceAsyn(d.Id(), ecs.Stopped, defaultTimeout); err != nil { + return fmt.Errorf("WaitForInstance %s got error: %#v", ecs.Stopped, err) + } + if vpcUpdate { + if err := conn.ModifyInstanceVpcAttribute(vpcArgs); err != nil { + return fmt.Errorf("ModifyInstanceVPCAttribute got an error: %#v.", err) + } + } + } else if instance.Status == ecs.Stopped { + if vpcUpdate { + if err := conn.ModifyInstanceVpcAttribute(vpcArgs); err != nil { + return fmt.Errorf("ModifyInstanceVPCAttribute got an error: %#v.", err) + } + } + } else { + return fmt.Errorf("ECS instance's status doesn't support to start or stop operation when chaning image_id or password or vpc attribute. The current instance's status is %#v", instance.Status) + } + + log.Printf("[DEBUG] Start instance after changing image or password or vpc attribute") + if err := conn.StartInstance(d.Id()); err != nil { + return fmt.Errorf("StartInstance got error: %#v", err) + } + + // Start instance sometimes costs more than 8 minutes when os type is centos. + if err := conn.WaitForInstance(d.Id(), ecs.Running, 500); err != nil { + return fmt.Errorf("WaitForInstance got error: %#v", err) + } + } + + if _, err := modifyInstanceChargeType(d, meta); err != nil { + return err + } + d.Partial(false) return resourceAliyunInstanceRead(d, meta) } @@ -511,7 +581,9 @@ func resourceAliyunInstanceUpdate(d *schema.ResourceData, meta interface{}) erro func resourceAliyunInstanceDelete(d *schema.ResourceData, meta interface{}) error { client := meta.(*AliyunClient) conn := client.ecsconn - + if common.InstanceChargeType(d.Get("instance_charge_type").(string)) == common.PrePaid { + return fmt.Errorf("'PrePaid' instance cannot be deleted.") + } return resource.Retry(5*time.Minute, func() *resource.RetryError { instance, err := client.QueryInstancesById(d.Id()) if err != nil { @@ -522,16 +594,16 @@ func resourceAliyunInstanceDelete(d *schema.ResourceData, meta interface{}) erro if instance.Status != ecs.Stopped { if err := conn.StopInstance(d.Id(), true); err != nil { - return resource.RetryableError(fmt.Errorf("ECS stop error - trying again.")) + return resource.RetryableError(fmt.Errorf("Stop instance timeout and got an error: %#v.", err)) } if err := conn.WaitForInstance(d.Id(), ecs.Stopped, defaultTimeout); err != nil { - return resource.RetryableError(fmt.Errorf("Waiting for ecs stopped timeout - trying again.")) + return resource.RetryableError(fmt.Errorf("Waiting for ecs stopped timeout and got an error: %#v.", err)) } } if err := conn.DeleteInstance(d.Id()); err != nil { - return resource.RetryableError(fmt.Errorf("ECS Instance in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete instance timeout and got an error: %#v.", err)) } return nil @@ -639,17 +711,18 @@ func buildAliyunInstanceArgs(d *schema.ResourceData, meta interface{}) (*ecs.Cre if d.Get("allocate_public_ip").(bool) && args.InternetMaxBandwidthOut <= 0 { return nil, fmt.Errorf("Invalid internet_max_bandwidth_out result in allocation public ip failed in the VPC.") } + if v, ok := d.GetOk("private_ip"); ok && v.(string) != "" { + args.PrivateIpAddress = v.(string) + } } if v := d.Get("instance_charge_type").(string); v != "" { args.InstanceChargeType = common.InstanceChargeType(v) } - log.Printf("[DEBUG] period is %d", d.Get("period").(int)) - if v := d.Get("period").(int); v != 0 { - args.Period = v - } else if args.InstanceChargeType == common.PrePaid { - return nil, fmt.Errorf("period is required for instance_charge_type is PrePaid") + if args.InstanceChargeType == common.PrePaid { + args.Period = d.Get("period").(int) + args.PeriodUnit = common.TimeType(d.Get("period_unit").(string)) } if v := d.Get("user_data").(string); v != "" { @@ -669,3 +742,31 @@ func buildAliyunInstanceArgs(d *schema.ResourceData, meta interface{}) (*ecs.Cre return args, nil } + +func modifyInstanceChargeType(d *schema.ResourceData, meta interface{}) (bool, error) { + conn := meta.(*AliyunClient).ecsconn + + if d.HasChange("instance_charge_type") && !d.IsNewResource() { + chargeType := d.Get("instance_charge_type").(string) + if common.InstanceChargeType(chargeType) == common.PostPaid { + return false, fmt.Errorf("Instance can't support to modify its charge type to 'PostPaid'.") + } + args := &ecs.ModifyInstanceChargeTypeArgs{ + InstanceIds: convertListToJsonString(append(make([]interface{}, 0, 1), d.Id())), + RegionId: getRegion(d, meta), + Period: d.Get("period").(int), + PeriodUnit: common.TimeType(d.Get("period_unit").(string)), + IncludeDataDisks: d.Get("include_data_disks").(bool), + AutoPay: true, + DryRun: d.Get("dry_run").(bool), + ClientToken: fmt.Sprintf("terraform-modify-instance-charge-type-%s", d.Id()), + } + if _, err := conn.ModifyInstanceChargeType(args); err != nil { + return false, fmt.Errorf("ModifyInstanceChareType got an error:%#v.", err) + } + d.SetPartial("instance_charge_type") + return true, nil + } + + return false, nil +} diff --git a/alicloud/resource_alicloud_instance_test.go b/alicloud/resource_alicloud_instance_test.go index daf700d6e8c..59c6eabe1fe 100644 --- a/alicloud/resource_alicloud_instance_test.go +++ b/alicloud/resource_alicloud_instance_test.go @@ -576,6 +576,74 @@ func TestAccAlicloudInstance_keyPair(t *testing.T) { }) } +func TestAccAlicloudInstancePrivateIp_update(t *testing.T) { + var instance ecs.InstanceAttributesType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckInstancePrivateIp, + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists("alicloud_instance.private_ip", &instance), + resource.TestCheckResourceAttr( + "alicloud_instance.private_ip", + "private_ip", + "10.1.1.3"), + ), + }, + + resource.TestStep{ + Config: testAccCheckInstancePrivateIpUpdate, + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists("alicloud_instance.private_ip", &instance), + resource.TestCheckResourceAttr( + "alicloud_instance.private_ip", + "private_ip", + "10.1.2.3"), + ), + }, + }, + }) +} + +func TestAccAlicloudInstanceChargeType_update(t *testing.T) { + var instance ecs.InstanceAttributesType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckInstanceChargeType, + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists("alicloud_instance.charge_type", &instance), + resource.TestCheckResourceAttr( + "alicloud_instance.charge_type", + "dry_run", "false"), + ), + }, + + resource.TestStep{ + Config: testAccCheckInstanceChargeTypeUpdate, + Check: resource.ComposeTestCheckFunc( + testAccCheckInstanceExists("alicloud_instance.charge_type", &instance), + resource.TestCheckResourceAttr( + "alicloud_instance.charge_type", + "dry_run", "true"), + ), + }, + }, + }) +} + func testAccCheckInstanceExists(n string, i *ecs.InstanceAttributesType) resource.TestCheckFunc { providers := []*schema.Provider{testAccProvider} return testAccCheckInstanceExistsWithProviders(n, i, &providers) @@ -1382,3 +1450,168 @@ resource "alicloud_instance" "key_pair" { key_name = "${alicloud_key_pair.key_pair.id}" } ` +const testAccCheckInstancePrivateIp = ` +data "alicloud_images" "ubuntu" { + most_recent = true + owners = "system" + name_regex = "^ubuntu_14\\w{1,5}[64]{1}.*" +} + +data "alicloud_zones" "zones" {} + +resource "alicloud_vpc" "foo" { + name = "tf_test_change_private" + cidr_block = "10.1.0.0/21" +} + +resource "alicloud_vswitch" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "10.1.1.0/24" + availability_zone = "${data.alicloud_zones.zones.zones.0.id}" +} + +resource "alicloud_vswitch" "bar" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "10.1.2.0/24" + availability_zone = "${data.alicloud_zones.zones.zones.0.id}" +} + +resource "alicloud_security_group" "group" { + name = "tf_test_private_ip" + vpc_id = "${alicloud_vpc.foo.id}" +} + +resource "alicloud_instance" "private_ip" { + image_id = "${data.alicloud_images.ubuntu.images.0.id}" + system_disk_category = "cloud_efficiency" + system_disk_size = 40 + + instance_type = "ecs.n4.small" + instance_name = "with_private_ip" + security_groups = ["${alicloud_security_group.group.id}"] + vswitch_id = "${alicloud_vswitch.foo.id}" + private_ip = "10.1.1.3" +} +` + +const testAccCheckInstancePrivateIpUpdate = ` +data "alicloud_images" "ubuntu" { + most_recent = true + owners = "system" + name_regex = "^ubuntu_14\\w{1,5}[64]{1}.*" +} + +data "alicloud_zones" "zones" {} + +resource "alicloud_vpc" "foo" { + name = "tf_test_change_private" + cidr_block = "10.1.0.0/21" +} + +resource "alicloud_vswitch" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "10.1.1.0/24" + availability_zone = "${data.alicloud_zones.zones.zones.0.id}" +} + +resource "alicloud_vswitch" "bar" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "10.1.2.0/24" + availability_zone = "${data.alicloud_zones.zones.zones.0.id}" +} + +resource "alicloud_security_group" "group" { + name = "tf_test_private_ip" + vpc_id = "${alicloud_vpc.foo.id}" +} + +resource "alicloud_instance" "private_ip" { + image_id = "${data.alicloud_images.ubuntu.images.0.id}" + system_disk_category = "cloud_efficiency" + system_disk_size = 40 + + instance_type = "ecs.n4.small" + instance_name = "with_private_ip" + security_groups = ["${alicloud_security_group.group.id}"] + vswitch_id = "${alicloud_vswitch.bar.id}" + private_ip = "10.1.2.3" +} +` + +const testAccCheckInstanceChargeType = ` +data "alicloud_images" "ubuntu" { + most_recent = true + owners = "system" + name_regex = "^ubuntu_14\\w{1,5}[64]{1}.*" +} + +data "alicloud_zones" "zones" {} + +resource "alicloud_vpc" "foo" { + name = "tf_test_charge_type" + cidr_block = "10.1.0.0/21" +} + +resource "alicloud_vswitch" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "10.1.1.0/24" + availability_zone = "${data.alicloud_zones.zones.zones.0.id}" +} + +resource "alicloud_security_group" "group" { + name = "tf_test_private_ip" + vpc_id = "${alicloud_vpc.foo.id}" +} + +resource "alicloud_instance" "charge_type" { + image_id = "${data.alicloud_images.ubuntu.images.0.id}" + system_disk_category = "cloud_efficiency" + system_disk_size = 40 + + instance_type = "ecs.n4.small" + instance_name = "with_charge_type" + security_groups = ["${alicloud_security_group.group.id}"] + vswitch_id = "${alicloud_vswitch.foo.id}" + private_ip = "10.1.1.3" +} +` + +const testAccCheckInstanceChargeTypeUpdate = ` +data "alicloud_images" "ubuntu" { + most_recent = true + owners = "system" + name_regex = "^ubuntu_14\\w{1,5}[64]{1}.*" +} + +data "alicloud_zones" "zones" {} + +resource "alicloud_vpc" "foo" { + name = "tf_test_charge_type" + cidr_block = "10.1.0.0/21" +} + +resource "alicloud_vswitch" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "10.1.1.0/24" + availability_zone = "${data.alicloud_zones.zones.zones.0.id}" +} + +resource "alicloud_security_group" "group" { + name = "tf_test_private_ip" + vpc_id = "${alicloud_vpc.foo.id}" +} + +resource "alicloud_instance" "charge_type" { + image_id = "${data.alicloud_images.ubuntu.images.0.id}" + system_disk_category = "cloud_efficiency" + system_disk_size = 40 + + instance_type = "ecs.n4.small" + instance_name = "with_charge_type" + security_groups = ["${alicloud_security_group.group.id}"] + vswitch_id = "${alicloud_vswitch.foo.id}" + private_ip = "10.1.1.3" + instance_charge_type = "PrePaid" + dry_run=true +} +` diff --git a/alicloud/resource_alicloud_key_pair.go b/alicloud/resource_alicloud_key_pair.go index 92cd64f13c5..87b595c5066 100644 --- a/alicloud/resource_alicloud_key_pair.go +++ b/alicloud/resource_alicloud_key_pair.go @@ -151,7 +151,7 @@ func resourceAlicloudKeyPairDelete(d *schema.ResourceData, meta interface{}) err return resource.NonRetryableError(err) } if len(instance_ids) > 0 { - return resource.RetryableError(fmt.Errorf("There is still attached instances -- try again to detach them.")) + return resource.RetryableError(fmt.Errorf("Delete Key Pair timeout and got an error: %#v.", err)) } err := client.ecsconn.DeleteKeyPairs(&ecs.DeleteKeyPairsArgs{ @@ -169,7 +169,7 @@ func resourceAlicloudKeyPairDelete(d *schema.ResourceData, meta interface{}) err KeyPairName: d.Id(), }) if len(keypairs) > 0 { - return resource.RetryableError(fmt.Errorf("Key Pair still exists - trying again.")) + return resource.RetryableError(fmt.Errorf("Delete Key Pair timeout and got an error: %#v.", err)) } return nil diff --git a/alicloud/resource_alicloud_key_pair_attachment.go b/alicloud/resource_alicloud_key_pair_attachment.go index ab53f472792..d3d982f8591 100644 --- a/alicloud/resource_alicloud_key_pair_attachment.go +++ b/alicloud/resource_alicloud_key_pair_attachment.go @@ -47,7 +47,7 @@ func resourceAlicloudKeyPairAttachmentCreate(d *schema.ResourceData, meta interf err := resource.Retry(5*time.Minute, func() *resource.RetryError { if er := conn.AttachKeyPair(args); er != nil { if IsExceptedError(er, KeyPairServiceUnavailable) { - return resource.RetryableError(fmt.Errorf("Key Pair is attaching and gets an error: %#v -- try again...", er)) + return resource.RetryableError(fmt.Errorf("Attach Key Pair timeout and got an error: %#v.", er)) } return resource.NonRetryableError(fmt.Errorf("Error Attach KeyPair: %#v", er)) } @@ -107,7 +107,7 @@ func resourceAlicloudKeyPairAttachmentDelete(d *schema.ResourceData, meta interf } if len(instance_ids) > 0 { instanceIds = convertListToJsonString(instance_ids) - return resource.RetryableError(fmt.Errorf("There is still attached instances -- try again to detach them.")) + return resource.RetryableError(fmt.Errorf("Detach Key Pair timeout and got an error: %#v.", err)) } return nil diff --git a/alicloud/resource_alicloud_nat_gateway.go b/alicloud/resource_alicloud_nat_gateway.go index 72415b04e76..5e80eef9d52 100644 --- a/alicloud/resource_alicloud_nat_gateway.go +++ b/alicloud/resource_alicloud_nat_gateway.go @@ -277,7 +277,7 @@ func resourceAliyunNatGatewayDelete(d *schema.ResourceData, meta interface{}) er } if retry { - return resource.RetryableError(fmt.Errorf("Bandwidth package in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete bandwidth package timeout and got an error: %#v.", err)) } args := &ecs.DeleteNatGatewayArgs{ @@ -289,7 +289,7 @@ func resourceAliyunNatGatewayDelete(d *schema.ResourceData, meta interface{}) er if err != nil { er, _ := err.(*common.Error) if er.ErrorResponse.Code == DependencyViolationBandwidthPackages { - return resource.RetryableError(fmt.Errorf("NatGateway in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete nat gateway timeout and got an error: %#v.", err)) } } @@ -306,7 +306,7 @@ func resourceAliyunNatGatewayDelete(d *schema.ResourceData, meta interface{}) er return nil } - return resource.RetryableError(fmt.Errorf("NatGateway in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete nat gateway timeout and got an error: %#v.", err)) }) } diff --git a/alicloud/resource_alicloud_router_interface.go b/alicloud/resource_alicloud_router_interface.go index d1295ce8e7e..d89df52b4dd 100644 --- a/alicloud/resource_alicloud_router_interface.go +++ b/alicloud/resource_alicloud_router_interface.go @@ -205,8 +205,7 @@ func resourceAlicloudRouterInterfaceDelete(d *schema.ResourceData, meta interfac if _, err := conn.DeleteRouterInterface(args); err != nil { if IsExceptedError(err, RouterInterfaceIncorrectStatus) || IsExceptedError(err, DependencyViolationRouterInterfaceReferedByRouteEntry) { time.Sleep(5 * time.Second) - //e, _ := err.(*common.Error) - return resource.RetryableError(fmt.Errorf("Router interface in use: %#v. Trying again while it is deleted.", err)) + return resource.RetryableError(fmt.Errorf("Delete router interface timeout and got an error: %#v.", err)) } return resource.NonRetryableError(fmt.Errorf("Error deleting interface %s: %#v", d.Id(), err)) } diff --git a/alicloud/resource_alicloud_security_group.go b/alicloud/resource_alicloud_security_group.go index 424309fe914..530bf891392 100644 --- a/alicloud/resource_alicloud_security_group.go +++ b/alicloud/resource_alicloud_security_group.go @@ -3,7 +3,6 @@ package alicloud import ( "fmt" - "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/ecs" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" @@ -81,7 +80,7 @@ func resourceAliyunSecurityGroupRead(d *schema.ResourceData, meta interface{}) e sg = group return nil } - return resource.RetryableError(fmt.Errorf("Security group is creating - try again while describe security group")) + return resource.RetryableError(fmt.Errorf("Create security group timeout and got an error: %#v", e)) }) if err != nil { @@ -142,9 +141,8 @@ func resourceAliyunSecurityGroupDelete(d *schema.ResourceData, meta interface{}) err := conn.DeleteSecurityGroup(getRegion(d, meta), d.Id()) if err != nil { - e, _ := err.(*common.Error) - if e.ErrorResponse.Code == SgDependencyViolation { - return resource.RetryableError(fmt.Errorf("Security group in use - trying again while it is deleted.")) + if IsExceptedError(err, SgDependencyViolation) { + return resource.RetryableError(fmt.Errorf("Delete security group timeout and got an error: %#v", err)) } } @@ -162,7 +160,7 @@ func resourceAliyunSecurityGroupDelete(d *schema.ResourceData, meta interface{}) return nil } - return resource.RetryableError(fmt.Errorf("Security group in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete security group timeout and got an error: %#v", err)) }) } diff --git a/alicloud/resource_alicloud_security_group_rule.go b/alicloud/resource_alicloud_security_group_rule.go index 01ac60cbdec..5d980520d93 100644 --- a/alicloud/resource_alicloud_security_group_rule.go +++ b/alicloud/resource_alicloud_security_group_rule.go @@ -243,7 +243,7 @@ func resourceAliyunSecurityGroupRuleDelete(d *schema.ResourceData, meta interfac if NotFoundError(err) || IsExceptedError(err, InvalidSecurityGroupIdNotFound) { return nil } - resource.RetryableError(fmt.Errorf("Security group rule in use - trying again while it is deleted.")) + resource.RetryableError(fmt.Errorf("Delete security group rule timeout and got an error: %#v", err)) } _, err = client.DescribeSecurityGroupRule(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], policy, priority) @@ -254,7 +254,7 @@ func resourceAliyunSecurityGroupRuleDelete(d *schema.ResourceData, meta interfac return resource.NonRetryableError(err) } - return resource.RetryableError(fmt.Errorf("Security group rule in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete security group rule timeout and got an error: %#v", err)) }) } diff --git a/alicloud/resource_alicloud_slb.go b/alicloud/resource_alicloud_slb.go index 7947093ca15..a22d0f60e40 100644 --- a/alicloud/resource_alicloud_slb.go +++ b/alicloud/resource_alicloud_slb.go @@ -24,34 +24,37 @@ func resourceAliyunSlb() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validateSlbName, - Computed: true, + Default: resource.PrefixedUniqueId("tf-lb-"), }, "internet": &schema.Schema{ Type: schema.TypeBool, Optional: true, ForceNew: true, + Default: false, }, "vswitch_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: slbInternetDiffSuppressFunc, }, "internet_charge_type": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Default: "paybytraffic", - ValidateFunc: validateSlbInternetChargeType, + Type: schema.TypeString, + Optional: true, + Default: slb.PayByTraffic, + ValidateFunc: validateSlbInternetChargeType, + DiffSuppressFunc: slbInternetChargeTypeDiffSuppressFunc, }, "bandwidth": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validateSlbBandwidth, - Computed: true, + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validateIntegerInRange(1, 1000), + Default: 1, + DiffSuppressFunc: slbBandwidthDiffSuppressFunc, }, "listener": &schema.Schema{ @@ -204,41 +207,33 @@ func resourceAliyunSlb() *schema.Resource { } func resourceAliyunSlbCreate(d *schema.ResourceData, meta interface{}) error { - slbconn := meta.(*AliyunClient).slbconn - - var slbName string - if v, ok := d.GetOk("name"); ok { - slbName = v.(string) - } else { - slbName = resource.PrefixedUniqueId("tf-lb-") - d.Set("name", slbName) + args := &slb.CreateLoadBalancerArgs{ + RegionId: getRegion(d, meta), + LoadBalancerName: d.Get("name").(string), + AddressType: slb.IntranetAddressType, + InternetChargeType: slb.PayByTraffic, } - - slbArgs := &slb.CreateLoadBalancerArgs{ - RegionId: getRegion(d, meta), - LoadBalancerName: slbName, - AddressType: slb.IntranetAddressType, + if d.Get("internet").(bool) { + args.AddressType = slb.InternetAddressType } - if internet, ok := d.GetOk("internet"); ok && internet.(bool) { - slbArgs.AddressType = slb.InternetAddressType + if v, ok := d.GetOk("internet_charge_type"); ok && v.(string) != "" { + args.InternetChargeType = slb.InternetChargeType(v.(string)) } - if v, ok := d.GetOk("internet_charge_type"); ok { - slbArgs.InternetChargeType = slb.InternetChargeType(v.(string)) + if v, ok := d.GetOk("vswitch_id"); ok && v.(string) != "" { + args.VSwitchId = v.(string) } if v, ok := d.GetOk("bandwidth"); ok && v.(int) != 0 { - slbArgs.Bandwidth = v.(int) + args.Bandwidth = v.(int) } - if v, ok := d.GetOk("vswitch_id"); ok { - slbArgs.VSwitchId = v.(string) - } - lb, err := slbconn.CreateLoadBalancer(slbArgs) + lb, err := slbconn.CreateLoadBalancer(args) + if err != nil { - return err + return fmt.Errorf("Create load balancer got an error: %#v", err) } d.SetId(lb.LoadBalancerId) @@ -251,15 +246,9 @@ func resourceAliyunSlbCreate(d *schema.ResourceData, meta interface{}) error { } func resourceAliyunSlbRead(d *schema.ResourceData, meta interface{}) error { - slbconn := meta.(*AliyunClient).slbconn - loadBalancer, err := slbconn.DescribeLoadBalancerAttribute(d.Id()) + loadBalancer, err := meta.(*AliyunClient).DescribeLoadBalancerAttribute(d.Id()) if err != nil { - if IsExceptedError(err, LoadBalancerNotFound) { - d.SetId("") - return nil - } - - return fmt.Errorf("Error describing load balancer failed: %#v", err) + return err } if loadBalancer == nil { @@ -288,29 +277,35 @@ func resourceAliyunSlbUpdate(d *schema.ResourceData, meta interface{}) error { d.Partial(true) - if d.HasChange("name") { - err := slbconn.SetLoadBalancerName(d.Id(), d.Get("name").(string)) - if err != nil { - return err + if d.HasChange("name") && !d.IsNewResource() { + if err := slbconn.SetLoadBalancerName(d.Id(), d.Get("name").(string)); err != nil { + return fmt.Errorf("SetLoadBalancerName got an error: %#v", err) } d.SetPartial("name") } - if d.Get("internet") == true && d.Get("internet_charge_type") == "paybybandwidth" { - //don't intranet web and paybybandwidth, then can modify bandwidth - if d.HasChange("bandwidth") { - args := &slb.ModifyLoadBalancerInternetSpecArgs{ - LoadBalancerId: d.Id(), - Bandwidth: d.Get("bandwidth").(int), - } - err := slbconn.ModifyLoadBalancerInternetSpec(args) - if err != nil { - return err - } + update := false + args := &slb.ModifyLoadBalancerInternetSpecArgs{ + LoadBalancerId: d.Id(), + } + if d.HasChange("internet_charge_type") && !d.IsNewResource() { + args.InternetChargeType = slb.InternetChargeType(d.Get("internet_charge_type").(string)) + update = true + d.SetPartial("internet_charge_type") + + } + if d.HasChange("bandwidth") && !d.IsNewResource() { + args.Bandwidth = d.Get("bandwidth").(int) + update = true + d.SetPartial("bandwidth") - d.SetPartial("bandwidth") + } + if update { + if err := slbconn.ModifyLoadBalancerInternetSpec(args); err != nil { + return fmt.Errorf("ModifyLoadBalancerInternetSpec got an error: %#v", err) } + } // If we currently have instances, or did have instances, @@ -369,7 +364,7 @@ func resourceAliyunSlbDelete(d *schema.ResourceData, meta interface{}) error { return resource.NonRetryableError(fmt.Errorf("Error describing slb failed when deleting SLB: %#v", err)) } if loadBalancer != nil { - return resource.RetryableError(fmt.Errorf("LoadBalancer in use - trying again while it deleted.")) + return resource.RetryableError(fmt.Errorf("Delete load balancer timeout and got an error: %#v.", err)) } return nil }) diff --git a/alicloud/resource_alicloud_slb_attachment.go b/alicloud/resource_alicloud_slb_attachment.go index fe9d7b3faeb..31e65e83288 100644 --- a/alicloud/resource_alicloud_slb_attachment.go +++ b/alicloud/resource_alicloud_slb_attachment.go @@ -42,20 +42,15 @@ func resourceAliyunSlbAttachment() *schema.Resource { func resourceAliyunSlbAttachmentCreate(d *schema.ResourceData, meta interface{}) error { - slbId := d.Get("slb_id").(string) - - slbconn := meta.(*AliyunClient).slbconn - - loadBalancer, err := slbconn.DescribeLoadBalancerAttribute(slbId) + loadBalancer, err := meta.(*AliyunClient).DescribeLoadBalancerAttribute(d.Get("slb_id").(string)) if err != nil { - if NotFoundError(err) { - d.SetId("") - return fmt.Errorf("Special SLB Id not found: %#v", err) - } - return err } + if loadBalancer == nil { + d.SetId("") + return fmt.Errorf("Special SLB Id %s is not found in %#v.", d.Get("slb_id").(string), getRegion(d, meta)) + } d.SetId(loadBalancer.LoadBalancerId) return resourceAliyunSlbAttachmentUpdate(d, meta) @@ -63,14 +58,9 @@ func resourceAliyunSlbAttachmentCreate(d *schema.ResourceData, meta interface{}) func resourceAliyunSlbAttachmentRead(d *schema.ResourceData, meta interface{}) error { - slbconn := meta.(*AliyunClient).slbconn - loadBalancer, err := slbconn.DescribeLoadBalancerAttribute(d.Id()) + loadBalancer, err := meta.(*AliyunClient).DescribeLoadBalancerAttribute(d.Get("slb_id").(string)) if err != nil { - if NotFoundError(err) { - d.SetId("") - return nil - } - return fmt.Errorf("Read special SLB Id not found: %#v", err) + return err } if loadBalancer == nil { @@ -112,7 +102,7 @@ func resourceAliyunSlbAttachmentUpdate(d *schema.ResourceData, meta interface{}) _, err := slbconn.AddBackendServers(d.Id(), add) if err != nil { if IsExceptedError(err, ServiceIsConfiguring) { - return resource.RetryableError(fmt.Errorf("Load banalcer is configuring - trying again while it is adding backend servers.")) + return resource.RetryableError(fmt.Errorf("Load banalcer adds backend servers timeout and got an error: %#v.", err)) } return resource.NonRetryableError(fmt.Errorf("Add backend servers got an error: %#v", err)) } @@ -150,7 +140,7 @@ func removeBackendServers(d *schema.ResourceData, meta interface{}, servers []sl _, err := slbconn.RemoveBackendServers(d.Id(), removeBackendServers) if err != nil { if IsExceptedError(err, BackendServerconfiguring) { - return resource.RetryableError(fmt.Errorf("Backend server is in use - trying again while it is detached.")) + return resource.RetryableError(fmt.Errorf("Load balancer removes backend servers timeout and got an error: %#v", err)) } return resource.NonRetryableError(fmt.Errorf("Remove backend servers got an error: %#v", err)) } diff --git a/alicloud/resource_alicloud_slb_listener.go b/alicloud/resource_alicloud_slb_listener.go index e60d01019dc..73ba01d9a93 100644 --- a/alicloud/resource_alicloud_slb_listener.go +++ b/alicloud/resource_alicloud_slb_listener.go @@ -481,6 +481,9 @@ func resourceAliyunSlbListenerDelete(d *schema.ResourceData, meta interface{}) e err := slbconn.DeleteLoadBalancerListener(lb_id, port) if err != nil { + if IsExceptedError(err, SystemBusy) { + resource.RetryableError(fmt.Errorf("Delete load balancer listener timeout and got an error: %#v.", err)) + } return resource.NonRetryableError(err) } @@ -690,7 +693,7 @@ func ensureListenerAbsent(d *schema.ResourceData, protocol string, listen interf return resource.NonRetryableError(fmt.Errorf("While deleting listener, DescribeLoadBalancer%sListenerAttribute got an error: %#v", protocol, err)) } if port := v.FieldByName("ListenerPort"); port.IsValid() && port.Interface().(int) > 0 { - return resource.RetryableError(fmt.Errorf("Listener in use - trying again while it deleted.")) + return resource.RetryableError(fmt.Errorf("Delete load balancer listener timeout and got an error: %#v.", err)) } d.SetId("") return nil diff --git a/alicloud/resource_alicloud_slb_listener_test.go b/alicloud/resource_alicloud_slb_listener_test.go index 486d58041e6..6f8bb8dcca5 100644 --- a/alicloud/resource_alicloud_slb_listener_test.go +++ b/alicloud/resource_alicloud_slb_listener_test.go @@ -106,7 +106,7 @@ func testAccCheckSlbListenerExists(n string, port int) resource.TestCheckFunc { parts := strings.Split(rs.Primary.ID, ":") loadBalancer, err := client.DescribeLoadBalancerAttribute(parts[0]) if err != nil { - return fmt.Errorf("DescribeLoadBalancerAttribute got an error: %#v", parts[0]) + return fmt.Errorf("DescribeLoadBalancerAttribute got an error: %#v", err) } for _, portAndProtocol := range loadBalancer.ListenerPortsAndProtocol.ListenerPortAndProtocol { if portAndProtocol.ListenerPort == port { diff --git a/alicloud/resource_alicloud_slb_test.go b/alicloud/resource_alicloud_slb_test.go index 4b24de0204f..f332aa737b7 100644 --- a/alicloud/resource_alicloud_slb_test.go +++ b/alicloud/resource_alicloud_slb_test.go @@ -2,7 +2,6 @@ package alicloud import ( "fmt" - "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/slb" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" @@ -146,12 +145,10 @@ func testAccCheckSlbDestroy(s *terraform.State) error { } if err != nil { - e, _ := err.(*common.Error) - // Verify the error is what we want - if e.ErrorResponse.Code != LoadBalancerNotFound { - return err + if IsExceptedError(err, LoadBalancerNotFound) { + return nil } - + return fmt.Errorf("DescribeLoadBalancerAttribute got an error: %#v", err) } } diff --git a/alicloud/resource_alicloud_vpc.go b/alicloud/resource_alicloud_vpc.go index 136dee228cf..be4ba2f80a3 100644 --- a/alicloud/resource_alicloud_vpc.go +++ b/alicloud/resource_alicloud_vpc.go @@ -87,7 +87,7 @@ func resourceAliyunVpcCreate(d *schema.ResourceData, meta interface{}) error { return resource.NonRetryableError(fmt.Errorf("The number of VPC has quota has reached the quota limit in your account, and please use existing VPCs or remove some of them.")) } if IsExceptedError(err, UnknownError) { - return resource.RetryableError(fmt.Errorf("Vpc is still creating result from some unknown error -- try again")) + return resource.RetryableError(fmt.Errorf("Create vpc timeout and got an error: %#v.", err)) } return resource.NonRetryableError(err) } @@ -184,7 +184,7 @@ func resourceAliyunVpcDelete(d *schema.ResourceData, meta interface{}) error { err := conn.DeleteVpc(d.Id()) if err != nil { - return resource.RetryableError(fmt.Errorf("Vpc in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete VPC timeout and got an error: %#v.", err)) } args := &ecs.DescribeVpcsArgs{ @@ -198,7 +198,7 @@ func resourceAliyunVpcDelete(d *schema.ResourceData, meta interface{}) error { return nil } - return resource.RetryableError(fmt.Errorf("Vpc in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete VPC timeout and got an error: %#v.", err)) }) } diff --git a/alicloud/resource_alicloud_vroute_entry.go b/alicloud/resource_alicloud_vroute_entry.go index 4189f39540c..d61d113624b 100644 --- a/alicloud/resource_alicloud_vroute_entry.go +++ b/alicloud/resource_alicloud_vroute_entry.go @@ -85,7 +85,7 @@ func resourceAliyunRouteEntryCreate(d *schema.ResourceData, meta interface{}) er // It must ensure all the route entries and vswitches' status must be available before creating or deleting route entry. if IsExceptedError(err, TaskConflict) || IsExceptedError(err, IncorrectRouteEntryStatus) { time.Sleep(5 * time.Second) - return resource.RetryableError(fmt.Errorf("Vroute entry is still creating -- try again, err:%#v", err)) + return resource.RetryableError(fmt.Errorf("Create route entry timeout and got an error: %#v", err)) } return resource.NonRetryableError(fmt.Errorf("Creating Route entry got an error: %#v", err)) } @@ -155,14 +155,14 @@ func resourceAliyunRouteEntryDelete(d *schema.ResourceData, meta interface{}) er } if en.Status != ecs.RouteEntryStatusAvailable { - return resource.RetryableError(fmt.Errorf("Waiting for RouteEntry's status is Available - trying again.")) + return resource.RetryableError(fmt.Errorf("Delete route entry timeout and got an error: %#v.", err)) } if err := conn.DeleteRouteEntry(args); err != nil { if IsExceptedError(err, TaskConflict) || IsExceptedError(err, IncorrectRouteEntryStatus) || IsExceptedError(err, RouterEntryForbbiden) { // Route Entry does not support creating or deleting within 5 seconds frequently time.Sleep(5 * time.Second) - return resource.RetryableError(fmt.Errorf("RouteEntry in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete route entry timeout and got an error: %#v.", err)) } return resource.NonRetryableError(fmt.Errorf("Deleting RouteEntry got an error: %#v", err)) } diff --git a/alicloud/resource_alicloud_vswitch.go b/alicloud/resource_alicloud_vswitch.go index 9bf76e8f0d6..36b8e38f42d 100644 --- a/alicloud/resource_alicloud_vswitch.go +++ b/alicloud/resource_alicloud_vswitch.go @@ -55,31 +55,28 @@ func resourceAliyunSwitchCreate(d *schema.ResourceData, meta interface{}) error conn := meta.(*AliyunClient).ecsconn var vswitchID, vpcID string - err := resource.Retry(3*time.Minute, func() *resource.RetryError { + if err := resource.Retry(3*time.Minute, func() *resource.RetryError { args, err := buildAliyunSwitchArgs(d, meta) if err != nil { return resource.NonRetryableError(fmt.Errorf("Building CreateVSwitchArgs got an error: %#v", err)) } vswId, err := conn.CreateVSwitch(args) if err != nil { - if e, ok := err.(*common.Error); ok && (e.StatusCode == 400 || e.Code == UnknownError) { - return resource.RetryableError(fmt.Errorf("Vswitch is still creating result from some unknown error -- try again")) + if IsExceptedError(err, UnknownError) { + return resource.RetryableError(fmt.Errorf("Creating Vswitch got an error: %#v", err)) } return resource.NonRetryableError(err) } vswitchID = vswId vpcID = args.VpcId return nil - }) - - if err != nil { - return fmt.Errorf("Create subnet got an error :%s", err) + }); err != nil { + return err } d.SetId(vswitchID) - err = conn.WaitForVSwitchAvailable(vpcID, vswitchID, 300) - if err != nil { + if err := conn.WaitForVSwitchAvailable(vpcID, vswitchID, 300); err != nil { return fmt.Errorf("WaitForVSwitchAvailable got a error: %s", err) } @@ -171,7 +168,7 @@ func resourceAliyunSwitchDelete(d *schema.ResourceData, meta interface{}) error return resource.NonRetryableError(err) } - return resource.RetryableError(fmt.Errorf("Switch in use. -- trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete vswitch timeout and got an error: %#v.", err)) } vsw, _, vswErr := conn.DescribeVSwitches(&ecs.DescribeVSwitchesArgs{ @@ -185,7 +182,7 @@ func resourceAliyunSwitchDelete(d *schema.ResourceData, meta interface{}) error return nil } - return resource.RetryableError(fmt.Errorf("Switch in use. -- trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete vswitch timeout and got an error: %#v.", err)) }) } diff --git a/alicloud/service_alicloud_ess.go b/alicloud/service_alicloud_ess.go index 645cb8a04ff..1bee2da1529 100644 --- a/alicloud/service_alicloud_ess.go +++ b/alicloud/service_alicloud_ess.go @@ -138,7 +138,7 @@ func (client *AliyunClient) DeleteScalingGroupById(sgId string) error { if err != nil { e, _ := err.(*common.Error) if e.ErrorResponse.Code != InvalidScalingGroupIdNotFound { - return resource.RetryableError(fmt.Errorf("Scaling group in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete scaling group timeout and got an error:%#v.", err)) } } @@ -150,6 +150,6 @@ func (client *AliyunClient) DeleteScalingGroupById(sgId string) error { return resource.NonRetryableError(err) } - return resource.RetryableError(fmt.Errorf("Scaling group in use - trying again while it is deleted.")) + return resource.RetryableError(fmt.Errorf("Delete scaling group timeout and got an error:%#v.", err)) }) } diff --git a/alicloud/service_alicloud_rds.go b/alicloud/service_alicloud_rds.go index b7b7d412053..f4844c51033 100644 --- a/alicloud/service_alicloud_rds.go +++ b/alicloud/service_alicloud_rds.go @@ -1,9 +1,12 @@ package alicloud import ( + "fmt" "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/rds" + "github.com/hashicorp/terraform/helper/resource" "strings" + "time" ) // @@ -32,90 +35,209 @@ func (client *AliyunClient) DescribeDBInstanceById(id string) (instance *rds.DBI attr := resp.Items.DBInstanceAttribute if len(attr) <= 0 { - return nil, GetNotFoundErrorFromString("DB instance not found") + return nil, GetNotFoundErrorFromString(fmt.Sprintf("DB instance %s is not found.", id)) } return &attr[0], nil } -func (client *AliyunClient) CreateAccountByInfo(instanceId, username, pwd string) error { +func (client *AliyunClient) DescribeDatabaseAccount(instanceId, accountName string) (ds *rds.DBInstanceAccount, err error) { conn := client.rdsconn - args := rds.CreateAccountArgs{ - DBInstanceId: instanceId, - AccountName: username, - AccountPassword: pwd, + resp, err := conn.DescribeAccounts(&rds.DescribeAccountsArgs{ + DBInstanceId: instanceId, + AccountName: accountName, + }) + + if err != nil { + return nil, err } - if _, err := conn.CreateAccount(&args); err != nil { - return err + if len(resp.Accounts.DBInstanceAccount) < 1 { + return nil, GetNotFoundErrorFromString(fmt.Sprintf("Data account %s is not found in the instance %s.", accountName, instanceId)) } + return &resp.Accounts.DBInstanceAccount[0], nil +} - if err := conn.WaitForAccount(instanceId, username, rds.Available, 200); err != nil { - return err +func (client *AliyunClient) DescribeDatabaseByName(instanceId, dbName string) (ds *rds.Database, err error) { + + resp, err := client.rdsconn.DescribeDatabases(&rds.DescribeDatabasesArgs{ + DBInstanceId: instanceId, + DBName: dbName, + }) + if err != nil { + return nil, err } - return nil + + if len(resp.Databases.Database) < 1 { + return nil, GetNotFoundErrorFromString(fmt.Sprintf("Database %s is not found in the instance %s.", dbName, instanceId)) + } + return &resp.Databases.Database[0], nil } -func (client *AliyunClient) CreateDatabaseByInfo(instanceId, dbName, charset, desp string) error { +func (client *AliyunClient) AllocateDBPublicConnection(instanceId, prefix, port string) error { conn := client.rdsconn - args := rds.CreateDatabaseArgs{ - DBInstanceId: instanceId, - DBName: dbName, - CharacterSetName: charset, - DBDescription: desp, + err := resource.Retry(3*time.Minute, func() *resource.RetryError { + if _, err := conn.AllocateInstancePublicConnection(&rds.AllocateInstancePublicConnectionArgs{ + DBInstanceId: instanceId, + ConnectionStringPrefix: prefix, + Port: port, + }); err != nil { + if IsExceptedError(err, NetTypeExists) { + connection, err := client.DescribeDBInstanceNetInfoByIpType(instanceId, rds.Public) + if err != nil { + return resource.NonRetryableError(err) + } + return resource.NonRetryableError(fmt.Errorf("The connection string with specified prefix %s has already existed. "+ + "Please import it using ID '%s:%s' or specify a new 'connection_prefix' and try again.", prefix, instanceId, connection.ConnectionString)) + } else if IsExceptedError(err, OperationDeniedDBInstanceStatus) { + return resource.RetryableError(fmt.Errorf("Allocate db connection got an error: %#v.", err)) + } + + return resource.NonRetryableError(fmt.Errorf("Allocate db connection got an error: %#v.", err)) + } + + return nil + }) + + if err != nil { + return err + } + + if err := conn.WaitForDBConnection(instanceId, rds.Public, 300); err != nil { + return err } - _, err := conn.CreateDatabase(&args) - return err + return nil } -func (client *AliyunClient) DescribeDatabaseByName(instanceId, dbName string) (ds []rds.Database, err error) { - conn := client.rdsconn - args := rds.DescribeDatabasesArgs{ +func (client *AliyunClient) DescribeDBInstanceNetInfos(instanceId string) ([]rds.DBInstanceNetInfo, error) { + + resp, err := client.rdsconn.DescribeDBInstanceNetInfo(&rds.DescribeDBInstanceNetInfoArgs{ DBInstanceId: instanceId, - DBName: dbName, + }) + + if err != nil { + return nil, err } - resp, err := conn.DescribeDatabases(&args) + if len(resp.DBInstanceNetInfos.DBInstanceNetInfo) < 1 { + return nil, GetNotFoundErrorFromString(fmt.Sprintf("DB instance %s does not have any connection.", instanceId)) + } + + return resp.DBInstanceNetInfos.DBInstanceNetInfo, nil +} + +func (client *AliyunClient) DescribeDBInstanceNetInfoByIpType(instanceId string, ipType rds.IPType) (*rds.DBInstanceNetInfo, error) { + + resps, err := client.DescribeDBInstanceNetInfos(instanceId) + if err != nil { return nil, err } - return resp.Databases.Database, nil + if len(resps) < 1 { + return nil, GetNotFoundErrorFromString(fmt.Sprintf("DB instance %s does not have any connection.", instanceId)) + } + + for _, conn := range resps { + if conn.IPType == ipType { + return &conn, nil + } + } + + return nil, GetNotFoundErrorFromString(fmt.Sprintf("DB instance %s does not have specified type %s connection.", instanceId, ipType)) } -func (client *AliyunClient) GrantDBPrivilege2Account(instanceId, username, dbName string) error { - conn := client.rdsconn - pargs := rds.GrantAccountPrivilegeArgs{ +func (client *AliyunClient) GrantAccountPrivilege(instanceId, account, dbName, privilege string) error { + args := rds.GrantAccountPrivilegeArgs{ DBInstanceId: instanceId, - AccountName: username, + AccountName: account, DBName: dbName, - AccountPrivilege: rds.ReadWrite, + AccountPrivilege: rds.AccountPrivilege(privilege), } - if _, err := conn.GrantAccountPrivilege(&pargs); err != nil { + + err := resource.Retry(3*time.Minute, func() *resource.RetryError { + ag := args + if _, err := client.rdsconn.GrantAccountPrivilege(&ag); err != nil { + if IsExceptedError(err, OperationDeniedDBInstanceStatus) { + return resource.RetryableError(fmt.Errorf("Grant DB %s account %s privilege got an error: %#v.", dbName, account, err)) + } + return resource.NonRetryableError(fmt.Errorf("Grant DB %s account %s privilege got an error: %#v.", dbName, account, err)) + } + return nil + }) + + if err != nil { return err } - if err := conn.WaitForAccountPrivilege(instanceId, username, dbName, rds.ReadWrite, 200); err != nil { + if err := client.rdsconn.WaitForAccountPrivilege(instanceId, account, dbName, rds.AccountPrivilege(privilege), 200); err != nil { + return fmt.Errorf("Wait for grantting DB %s account %s privilege got an error: %#v.", dbName, account, err) + } + + return nil +} + +func (client *AliyunClient) RevokeAccountPrivilege(instanceId, account, dbName string) error { + args := rds.RevokeAccountPrivilegeArgs{ + DBInstanceId: instanceId, + AccountName: account, + DBName: dbName, + } + + err := resource.Retry(3*time.Minute, func() *resource.RetryError { + ag := args + if err := client.rdsconn.RevokeAccountPrivilege(&ag); err != nil { + if IsExceptedError(err, OperationDeniedDBInstanceStatus) { + return resource.RetryableError(fmt.Errorf("Revoke DB %s account %s privilege got an error: %#v.", dbName, account, err)) + } + return resource.NonRetryableError(fmt.Errorf("Revoke DB %s account %s privilege got an error: %#v.", dbName, account, err)) + } + return nil + }) + + if err != nil { return err } + + if err := client.rdsconn.WaitForAccountPrivilegeRevoked(instanceId, account, dbName, 200); err != nil { + return fmt.Errorf("Wait for revoking DB %s account %s privilege got an error: %#v.", dbName, account, err) + } + return nil } -func (client *AliyunClient) AllocateDBPublicConnection(instanceId, port string) error { +func (client *AliyunClient) ReleaseDBPublicConnection(instanceId, connection string) error { conn := client.rdsconn - args := rds.AllocateInstancePublicConnectionArgs{ + + if err := conn.ReleaseInstancePublicConnection(&rds.ReleaseInstancePublicConnectionArgs{ + DBInstanceId: instanceId, + CurrentConnectionString: connection, + }); err != nil { + return err + } + return nil +} + +func (client *AliyunClient) SwitchDBInstanceNetType(instanceId, prefix string, port int, vswitchId string) error { + conn := client.rdsconn + + if err := conn.SwitchDBInstanceNetType(&rds.SwitchDBInstanceNetTypeArgs{ DBInstanceId: instanceId, - ConnectionStringPrefix: instanceId + "o", + ConnectionStringPrefix: prefix, Port: port, + }); err != nil { + return err } - if _, err := conn.AllocateInstancePublicConnection(&args); err != nil { - return err + ipType := rds.Private + if vswitchId == "" { + ipType = rds.Inner } - if err := conn.WaitForPublicConnection(instanceId, 600); err != nil { + if err := conn.WaitForDBConnection(instanceId, ipType, 300); err != nil { return err } + return nil } diff --git a/alicloud/service_alicloud_slb.go b/alicloud/service_alicloud_slb.go index 27dffe3b137..3241e6d6eca 100644 --- a/alicloud/service_alicloud_slb.go +++ b/alicloud/service_alicloud_slb.go @@ -5,17 +5,14 @@ import ( ) func (client *AliyunClient) DescribeLoadBalancerAttribute(slbId string) (*slb.LoadBalancerType, error) { - loadBalancer, err := client.slbconn.DescribeLoadBalancerAttribute(slbId) + + loadBalancer, err := client.slbconn.NewDescribeLoadBalancerAttribute(&slb.NewDescribeLoadBalancerAttributeArgs{ + RegionId: client.Region, + LoadBalancerId: slbId, + }) + if err != nil { - if NotFoundError(err) { - return nil, nil - } return nil, err } - - if loadBalancer != nil { - return loadBalancer, nil - } - - return nil, nil + return loadBalancer, nil } diff --git a/alicloud/validators.go b/alicloud/validators.go index 913459ee823..ed3dec8d05e 100644 --- a/alicloud/validators.go +++ b/alicloud/validators.go @@ -301,6 +301,25 @@ func validateInternetMaxBandWidthOut(v interface{}, k string) (ws []string, erro return } +func validateInstanceChargeTypePeriod(v interface{}, k string) (ws []string, errors []error) { + value := v.(int) + if (value > 0 && value < 10) || (value > 11 && value < 61 && value%12 == 0) { + return + } + errors = append(errors, fmt.Errorf( + "%q must be a valid period, expected [1-9], 12, 24, 36, 48 or 60, got %d.", k, value)) + return +} +func validateInstanceChargeTypePeriodUnit(v interface{}, k string) (ws []string, errors []error) { + unit := common.TimeType(v.(string)) + if unit != common.Week && unit != common.Month { + errors = append(errors, fmt.Errorf( + "%q must contain a valid PeriodUnit, expected %s or %s, got %s.", + k, common.Week, common.Month, unit)) + } + return +} + // SLB func validateSlbName(v interface{}, k string) (ws []string, errors []error) { if value := v.(string); value != "" { @@ -330,17 +349,6 @@ func validateSlbInternetChargeType(v interface{}, k string) (ws []string, errors return } -func validateSlbBandwidth(v interface{}, k string) (ws []string, errors []error) { - value := v.(int) - if value < 1 || value > 1000 { - errors = append(errors, fmt.Errorf( - "%q must be a valid load balancer bandwidth between 1 and 1000", - k)) - return - } - return -} - func validateSlbListenerBandwidth(v interface{}, k string) (ws []string, errors []error) { value := v.(int) if (value < 1 || value > 1000) && value != -1 { @@ -1045,3 +1053,16 @@ func validateInstanceType(v interface{}, k string) (ws []string, errors []error) } return } + +func validateDBConnectionPort(v interface{}, k string) (ws []string, errors []error) { + if value := v.(string); value != "" { + port, err := strconv.Atoi(value) + if err != nil { + errors = append(errors, err) + } + if port < 3001 || len(value) > 3999 { + errors = append(errors, fmt.Errorf("%q cannot be less than 3001 and larger than 3999.", k)) + } + } + return +} diff --git a/alicloud/validators_test.go b/alicloud/validators_test.go index de135506c98..94515f350cf 100644 --- a/alicloud/validators_test.go +++ b/alicloud/validators_test.go @@ -392,24 +392,6 @@ func TestValidateSlbInternetChargeType(t *testing.T) { } } -func TestValidateSlbBandwidth(t *testing.T) { - validSlbBandwidth := []int{1, 22, 1000} - for _, v := range validSlbBandwidth { - _, errors := validateSlbBandwidth(v, "slb_bandwidth") - if len(errors) != 0 { - t.Fatalf("%q should be a valid slb bandwidth value: %q", v, errors) - } - } - - invalidSlbBandwidth := []int{-2, 0, 1001} - for _, v := range invalidSlbBandwidth { - _, errors := validateSlbBandwidth(v, "slb_bandwidth") - if len(errors) == 0 { - t.Fatalf("%q should be an invalid slb bandwidth value", v) - } - } -} - func TestValidateSlbListenerBandwidth(t *testing.T) { validSlbListenerBandwidth := []int{-1, 1, 22, 1000} for _, v := range validSlbListenerBandwidth { diff --git a/vendor/github.com/denverdino/aliyungo/common/endpoints.xml b/vendor/github.com/denverdino/aliyungo/common/endpoints.xml index 4079bcd2b50..21f3a0b2e6b 100644 --- a/vendor/github.com/denverdino/aliyungo/common/endpoints.xml +++ b/vendor/github.com/denverdino/aliyungo/common/endpoints.xml @@ -1346,4 +1346,14 @@ Slbslb.cn-zhangjiakou.aliyuncs.com + + cn-huhehaote + + Rdsrds.cn-huhehaote.aliyuncs.com + Ecsecs.cn-huhehaote.aliyuncs.com + Vpcvpc.cn-huhehaote.aliyuncs.com + Cmsmetrics.cn-hangzhou.aliyuncs.com + Slbslb.cn-huhehaote.aliyuncs.com + + diff --git a/vendor/github.com/denverdino/aliyungo/common/regions.go b/vendor/github.com/denverdino/aliyungo/common/regions.go index 199ee5915d3..364469b0609 100644 --- a/vendor/github.com/denverdino/aliyungo/common/regions.go +++ b/vendor/github.com/denverdino/aliyungo/common/regions.go @@ -12,6 +12,7 @@ const ( Shenzhen = Region("cn-shenzhen") Shanghai = Region("cn-shanghai") Zhangjiakou = Region("cn-zhangjiakou") + Huhehaote = Region("cn-huhehaote") APSouthEast1 = Region("ap-southeast-1") APNorthEast1 = Region("ap-northeast-1") @@ -30,7 +31,7 @@ const ( ) var ValidRegions = []Region{ - Hangzhou, Qingdao, Beijing, Shenzhen, Hongkong, Shanghai, Zhangjiakou, + Hangzhou, Qingdao, Beijing, Shenzhen, Hongkong, Shanghai, Zhangjiakou, Huhehaote, USWest1, USEast1, APNorthEast1, APSouthEast1, APSouthEast2, APSouthEast3, MEEast1, diff --git a/vendor/github.com/denverdino/aliyungo/common/types.go b/vendor/github.com/denverdino/aliyungo/common/types.go index a74e150e9f1..753e74c5945 100644 --- a/vendor/github.com/denverdino/aliyungo/common/types.go +++ b/vendor/github.com/denverdino/aliyungo/common/types.go @@ -48,6 +48,7 @@ type TimeType string const ( Hour = TimeType("Hour") Day = TimeType("Day") + Week = TimeType("Week") Month = TimeType("Month") Year = TimeType("Year") ) diff --git a/vendor/github.com/denverdino/aliyungo/ecs/instances.go b/vendor/github.com/denverdino/aliyungo/ecs/instances.go index 74be6e50130..065416d2722 100644 --- a/vendor/github.com/denverdino/aliyungo/ecs/instances.go +++ b/vendor/github.com/denverdino/aliyungo/ecs/instances.go @@ -555,6 +555,7 @@ type CreateInstanceArgs struct { ClientToken string InstanceChargeType common.InstanceChargeType Period int + PeriodUnit common.TimeType UserData string AutoRenew bool AutoRenewPeriod int @@ -704,3 +705,71 @@ func (client *Client) DescribeInstanceRamRole(args *AttachInstancesArgs) (resp * } return response, nil } + +type ModifyInstanceSpecArgs struct { + InstanceId string + InstanceType string + InternetMaxBandwidthOut *int + InternetMaxBandwidthIn *int + ClientToken string +} + +type ModifyInstanceSpecResponse struct { + common.Response +} + +//ModifyInstanceSpec modify instance specification +// +// Notice: 1. An instance that was successfully modified once cannot be modified again within 5 minutes. +// 2. The API only can be used Pay-As-You-Go (PostPaid) instance +// +// You can read doc at https://www.alibabacloud.com/help/doc-detail/57633.htm +func (client *Client) ModifyInstanceSpec(args *ModifyInstanceSpecArgs) error { + response := ModifyInstanceSpecResponse{} + return client.Invoke("ModifyInstanceSpec", args, &response) +} + +type ModifyInstanceVpcAttributeArgs struct { + InstanceId string + VSwitchId string + PrivateIpAddress string +} + +type ModifyInstanceVpcAttributeResponse struct { + common.Response +} + +//ModifyInstanceVpcAttribute modify instance vswitchID and private ip address +// +// You can read doc at https://www.alibabacloud.com/help/doc-detail/25504.htm +func (client *Client) ModifyInstanceVpcAttribute(args *ModifyInstanceVpcAttributeArgs) error { + response := ModifyInstanceVpcAttributeResponse{} + return client.Invoke("ModifyInstanceVpcAttribute", args, &response) +} + +type ModifyInstanceChargeTypeArgs struct { + InstanceIds string + RegionId common.Region + Period int + PeriodUnit common.TimeType + IncludeDataDisks bool + DryRun bool + AutoPay bool + ClientToken string +} + +type ModifyInstanceChargeTypeResponse struct { + common.Response + Order string +} + +//ModifyInstanceChargeType modify instance charge type +// +// You can read doc at https://www.alibabacloud.com/help/doc-detail/25504.htm +func (client *Client) ModifyInstanceChargeType(args *ModifyInstanceChargeTypeArgs) (*ModifyInstanceChargeTypeResponse, error) { + response := &ModifyInstanceChargeTypeResponse{} + if err := client.Invoke("ModifyInstanceChargeType", args, response); err != nil { + return response, err + } + return response, nil +} \ No newline at end of file diff --git a/vendor/github.com/denverdino/aliyungo/ecs/networks.go b/vendor/github.com/denverdino/aliyungo/ecs/networks.go index 4c4cd7150de..028dbe6c2df 100644 --- a/vendor/github.com/denverdino/aliyungo/ecs/networks.go +++ b/vendor/github.com/denverdino/aliyungo/ecs/networks.go @@ -128,6 +128,7 @@ type EipAddressSetType struct { AllocationId string Status EipStatus InstanceId string + InstanceType string Bandwidth string // Why string InternetChargeType common.InternetChargeType OperationLocks OperationLocksType diff --git a/vendor/github.com/denverdino/aliyungo/rds/instances.go b/vendor/github.com/denverdino/aliyungo/rds/instances.go index 55b13ba57de..481b388d304 100644 --- a/vendor/github.com/denverdino/aliyungo/rds/instances.go +++ b/vendor/github.com/denverdino/aliyungo/rds/instances.go @@ -100,6 +100,7 @@ type ConnectionMode string const ( Performance = ConnectionMode("Performance") Safty = ConnectionMode("Safty") + Standard = ConnectionMode("Standard") ) // default resource value for create order @@ -323,6 +324,7 @@ type DBInstanceAccount struct { DatabasePrivileges struct { DatabasePrivilege []DatabasePrivilege } + AccountType AccountType } type AccountStatus string @@ -545,6 +547,42 @@ func (client *Client) WaitForPublicConnection(instanceId string, timeout int) er return nil } +func (client *Client) WaitForDBConnection(instanceId string, netType IPType, timeout int) error { + if timeout <= 0 { + timeout = InstanceDefaultTimeout + } + for { + args := DescribeDBInstanceNetInfoArgs{ + DBInstanceId: instanceId, + } + + resp, err := client.DescribeDBInstanceNetInfo(&args) + if err != nil { + return err + } + + if timeout <= 0 { + return common.GetClientErrorFromString("Timeout") + } + + timeout = timeout - DefaultWaitForInterval + time.Sleep(DefaultWaitForInterval * time.Second) + + ready := false + for _, info := range resp.DBInstanceNetInfos.DBInstanceNetInfo { + if info.IPType == netType { + ready = true + } + } + + if ready { + break + } + + } + return nil +} + func (client *Client) WaitForAccountPrivilege(instanceId, accountName, dbName string, privilege AccountPrivilege, timeout int) error { if timeout <= 0 { timeout = InstanceDefaultTimeout @@ -590,6 +628,53 @@ func (client *Client) WaitForAccountPrivilege(instanceId, accountName, dbName st return nil } +func (client *Client) WaitForAccountPrivilegeRevoked(instanceId, accountName, dbName string, timeout int) error { + if timeout <= 0 { + timeout = InstanceDefaultTimeout + } + for { + args := DescribeAccountsArgs{ + DBInstanceId: instanceId, + AccountName: accountName, + } + + resp, err := client.DescribeAccounts(&args) + if err != nil { + return err + } + + accs := resp.Accounts.DBInstanceAccount + + if len(accs) < 1 { + continue + } + + acc := accs[0] + + exist := false + for _, dp := range acc.DatabasePrivileges.DatabasePrivilege { + if dp.DBName == dbName { + exist = true + break + } + } + + if !exist { + break + } + + if timeout <= 0 { + return common.GetClientErrorFromString("Timeout") + } + + timeout = timeout - DefaultWaitForInterval + time.Sleep(DefaultWaitForInterval * time.Second) + + } + return nil +} + + type DeleteDBInstanceArgs struct { DBInstanceId string } @@ -682,6 +767,19 @@ func (client *Client) CreateDatabase(args *CreateDatabaseArgs) (resp *CreateData return &response, nil } +type ModifyDatabaseDescriptionArgs struct { + DBInstanceId string + DBName string + DBDescription string +} + +// ModifyDBDescription create rds database description +// +func (client *Client) ModifyDatabaseDescription(args *ModifyDatabaseDescriptionArgs) error { + response := common.Response{} + return client.Invoke("ModifyDBDescription", args, &response) +} + type CreateAccountResponse struct { common.Response } @@ -739,6 +837,19 @@ func (client *Client) ResetAccountPassword(instanceId, accountName, accountPassw return &response, nil } +type ModifyAccountDescriptionArgs struct { + DBInstanceId string + AccountName string + AccountDescription string +} + +// ModifyDBDescription create rds database description +// +func (client *Client) ModifyAccountDescription(args *ModifyAccountDescriptionArgs) error { + response := common.Response{} + return client.Invoke("ModifyAccountDescription", args, &response) +} + type DeleteAccountResponse struct { common.Response } @@ -797,6 +908,21 @@ func (client *Client) GrantAccountPrivilege(args *GrantAccountPrivilegeArgs) (re return &response, nil } +type RevokeAccountPrivilegeArgs struct { + DBInstanceId string + AccountName string + DBName string +} + +// RevokeAccountPrivilege revoke database privilege from account +// +// You can read doc at https://help.aliyun.com/document_detail/26267.html +func (client *Client) RevokeAccountPrivilege(args *RevokeAccountPrivilegeArgs) error { + response := common.Response{} + return client.Invoke("RevokeAccountPrivilege", args, &response) +} + + type AllocateInstancePublicConnectionResponse struct { common.Response } @@ -820,8 +946,37 @@ func (client *Client) AllocateInstancePublicConnection(args *AllocateInstancePub return &response, nil } +type ReleaseInstancePublicConnectionArgs struct { + DBInstanceId string + CurrentConnectionString string +} + +func (client *Client) ReleaseInstancePublicConnection(args *ReleaseInstancePublicConnectionArgs) error{ + response := common.Response{} + return client.Invoke("ReleaseInstancePublicConnection", args, &response) +} + +type SwitchDBInstanceNetTypeArgs struct { + DBInstanceId string + ConnectionStringPrefix string + Port int +} + +func (client *Client) SwitchDBInstanceNetType(args *SwitchDBInstanceNetTypeArgs) error{ + response := common.Response{} + return client.Invoke("SwitchDBInstanceNetType", args, &response) +} + +type ConnectionStringType string + +const ( + ConnectionNormal = ConnectionStringType("Normal") + ReadWriteSplitting = ConnectionStringType("ReadWriteSplitting") +) + type DescribeDBInstanceNetInfoArgs struct { DBInstanceId string + ConnectionStringType ConnectionStringType } type DescribeDBInstanceNetInfoResponse struct { @@ -862,6 +1017,21 @@ func (client *Client) DescribeDBInstanceNetInfo(args *DescribeDBInstanceNetInfoA return &response, nil } +type ModifyDBInstanceConnectionStringArgs struct { + DBInstanceId string + CurrentConnectionString string + ConnectionStringPrefix string + Port string +} + +// ModifyDBInstanceConnectionString modify rds connection string +// +// You can read doc at https://help.aliyun.com/document_detail/26238.html +func (client *Client) ModifyDBInstanceConnectionString(args *ModifyDBInstanceConnectionStringArgs) error { + response := common.Response{} + return client.Invoke("ModifyDBInstanceConnectionString", args, &response) +} + type BackupPolicy struct { PreferredBackupTime string // HH:mmZ - HH:mm Z PreferredBackupPeriod string // Monday - Sunday diff --git a/vendor/github.com/denverdino/aliyungo/slb/loadbalancers.go b/vendor/github.com/denverdino/aliyungo/slb/loadbalancers.go index ec2befc3967..31555c01d00 100644 --- a/vendor/github.com/denverdino/aliyungo/slb/loadbalancers.go +++ b/vendor/github.com/denverdino/aliyungo/slb/loadbalancers.go @@ -241,6 +241,27 @@ func (client *Client) DescribeLoadBalancerAttribute(loadBalancerId string) (load return &response.LoadBalancerType, err } +type NewDescribeLoadBalancerAttributeArgs struct { + LoadBalancerId string + RegionId common.Region + MasterZoneId string + SlaveZoneId string +} + +// New DescribeLoadBalancerAttribute to describe loadbalancer attribute using regionId avoiding to get not found error +// +// You can read doc at https://www.alibabacloud.com/help/doc-detail/27583.htm + +func (client *Client) NewDescribeLoadBalancerAttribute(args *NewDescribeLoadBalancerAttributeArgs) (loadBalancer *LoadBalancerType, err error) { + + response := &DescribeLoadBalancerAttributeResponse{} + err = client.Invoke("DescribeLoadBalancerAttribute", args, response) + if err != nil { + return nil, err + } + return &response.LoadBalancerType, err +} + // WaitForListener waits for listener to given status func (client *Client) WaitForLoadBalancerAsyn(loadBalancerId string, status Status, timeout int) error { if timeout <= 0 { diff --git a/vendor/vendor.json b/vendor/vendor.json index fc294e8905b..e6077f84d25 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -235,68 +235,68 @@ { "checksumSHA1": "9JK6TQ6tSG68roB1KWs3NIxw6zY=", "path": "github.com/denverdino/aliyungo/cdn", - "revision": "df1711e43f18d55672c2ca12b3a27a1a2d753aa6", - "revisionTime": "2017-12-14T00:42:06Z" + "revision": "c6b4a0eeeea44d34172cfa2befd3182ef3f855b8", + "revisionTime": "2018-01-03T07:30:43Z" }, { - "checksumSHA1": "qvFutFkayxTxJN3E1AENo4kHEzA=", + "checksumSHA1": "GSno/BaFkWDMyhlsrePa6ylcJG0=", "path": "github.com/denverdino/aliyungo/common", - "revision": "df1711e43f18d55672c2ca12b3a27a1a2d753aa6", - "revisionTime": "2017-12-14T00:42:06Z" + "revision": "c6b4a0eeeea44d34172cfa2befd3182ef3f855b8", + "revisionTime": "2018-01-03T07:30:43Z" }, { "checksumSHA1": "iINyIl3tdnJ1149OjjDIYM8o7gk=", "path": "github.com/denverdino/aliyungo/cs", - "revision": "df1711e43f18d55672c2ca12b3a27a1a2d753aa6", - "revisionTime": "2017-12-14T00:42:06Z" + "revision": "c6b4a0eeeea44d34172cfa2befd3182ef3f855b8", + "revisionTime": "2018-01-03T07:30:43Z" }, { "checksumSHA1": "r3LvtjLkVZzM8X1HKSOznMs2FSA=", "path": "github.com/denverdino/aliyungo/dns", - "revision": "df1711e43f18d55672c2ca12b3a27a1a2d753aa6", - "revisionTime": "2017-12-14T00:42:06Z" + "revision": "c6b4a0eeeea44d34172cfa2befd3182ef3f855b8", + "revisionTime": "2018-01-03T07:30:43Z" }, { - "checksumSHA1": "dRCnl3Jccqs69IUO8s90ZUez/Vc=", + "checksumSHA1": "i7OrkPMQ0OMPGKrktSQp3zK7z44=", "path": "github.com/denverdino/aliyungo/ecs", - "revision": "df1711e43f18d55672c2ca12b3a27a1a2d753aa6", - "revisionTime": "2017-12-14T00:42:06Z" + "revision": "c6b4a0eeeea44d34172cfa2befd3182ef3f855b8", + "revisionTime": "2018-01-03T07:30:43Z" }, { "checksumSHA1": "VH9KnFDd2UcZcldPHlOmMM8kNJ4=", "path": "github.com/denverdino/aliyungo/ess", - "revision": "df1711e43f18d55672c2ca12b3a27a1a2d753aa6", - "revisionTime": "2017-12-14T00:42:06Z" + "revision": "c6b4a0eeeea44d34172cfa2befd3182ef3f855b8", + "revisionTime": "2018-01-03T07:30:43Z" }, { "checksumSHA1": "CPuR3s7LzQkT57Z20zMHXQM2MYQ=", "path": "github.com/denverdino/aliyungo/location", - "revision": "df1711e43f18d55672c2ca12b3a27a1a2d753aa6", - "revisionTime": "2017-12-14T00:42:06Z" + "revision": "c6b4a0eeeea44d34172cfa2befd3182ef3f855b8", + "revisionTime": "2018-01-03T07:30:43Z" }, { "checksumSHA1": "sievsBvgtVF2iZ2FjmDZppH3+Ro=", "path": "github.com/denverdino/aliyungo/ram", - "revision": "df1711e43f18d55672c2ca12b3a27a1a2d753aa6", - "revisionTime": "2017-12-14T00:42:06Z" + "revision": "c6b4a0eeeea44d34172cfa2befd3182ef3f855b8", + "revisionTime": "2018-01-03T07:30:43Z" }, { - "checksumSHA1": "5muc4YGlXvIK6BwWNXQppIEcEkg=", + "checksumSHA1": "ghu+g3Ry+kEo2J6Fi3dq4sPgKms=", "path": "github.com/denverdino/aliyungo/rds", - "revision": "df1711e43f18d55672c2ca12b3a27a1a2d753aa6", - "revisionTime": "2017-12-14T00:42:06Z" + "revision": "c6b4a0eeeea44d34172cfa2befd3182ef3f855b8", + "revisionTime": "2018-01-03T07:30:43Z" }, { - "checksumSHA1": "F5E3P7vRGp5scgJQHewQcw+xPjs=", + "checksumSHA1": "9BH/hmTscysPpo65oBKkBd0qXqc=", "path": "github.com/denverdino/aliyungo/slb", - "revision": "df1711e43f18d55672c2ca12b3a27a1a2d753aa6", - "revisionTime": "2017-12-14T00:42:06Z" + "revision": "c6b4a0eeeea44d34172cfa2befd3182ef3f855b8", + "revisionTime": "2018-01-03T07:30:43Z" }, { "checksumSHA1": "cKVBRn7GKT+0IqfGUc/NnKDWzCw=", "path": "github.com/denverdino/aliyungo/util", - "revision": "df1711e43f18d55672c2ca12b3a27a1a2d753aa6", - "revisionTime": "2017-12-14T00:42:06Z" + "revision": "c6b4a0eeeea44d34172cfa2befd3182ef3f855b8", + "revisionTime": "2018-01-03T07:30:43Z" }, { "checksumSHA1": "BCv50o5pDkoSG3vYKOSai1Z8p3w=", diff --git a/website/docs/r/db_instance.html.markdown b/website/docs/r/db_instance.html.markdown index e5b7a7404ae..310a22e9ded 100644 --- a/website/docs/r/db_instance.html.markdown +++ b/website/docs/r/db_instance.html.markdown @@ -8,20 +8,18 @@ description: |- # alicloud\_db\_instance -Provides an RDS instance resource. A DB instance is an isolated database -environment in the cloud. A DB instance can contain multiple user-created +Provides an RDS instance resource. A DB instance is an isolated database +environment in the cloud. A DB instance can contain multiple user-created databases. ## Example Usage ``` resource "alicloud_db_instance" "default" { - commodity_code = "rds" engine = "MySQL" engine_version = "5.6" db_instance_class = "rds.mysql.t1.small" db_instance_storage = "10" - db_instance_net_type = "Intranet" } ``` @@ -35,52 +33,33 @@ The following arguments are supported: - 2008r2/2012 for SQLServer - 9.4 for PostgreSQL - 9.3 for PPAS -* `db_instance_class` - (Required) Instance type. For details, see [Instance type table](https://intl.aliyun.com/help/doc-detail/26312.htm?spm=a3c0i.o26228en.a3.2.bRUHF3). -* `db_instance_storage` - (Required) User-defined storage space. Value range: +* `db_instance_class` - (Deprecated) It has been deprecated from version 1.5.0 and use 'instance_type' to replace. +* `instance_type` - (Required) DB Instance type. For details, see [Instance type table](https://www.alibabacloud.com/help/doc-detail/26312.htm). +* `db_instance_storage` - (Deprecated) It has been deprecated from version 1.5.0 and use 'instance_storage' to replace. +* `instance_storage` - (Required) User-defined DB instance storage space. Value range: - [5, 2000] for MySQL/PostgreSQL/PPAS HA dual node edition; - [20,1000] for MySQL 5.7 basic single node edition; - [10, 2000] for SQL Server 2008R2; - [20,2000] for SQL Server 2012 basic single node edition - Increase progressively at a rate of 5 GB. The unit is GB. For details, see [Instance type table](https://intl.aliyun.com/help/doc-detail/26312.htm?spm=a3c0i.o26228en.a3.3.bRUHF3). -* `instance_charge_type` - (Optional) Valid values are `Prepaid`, `Postpaid`, The default is `Postpaid`. -* `period` - (Optional) The time that you have bought the resource, in month. Only valid when instance_charge_type is set as `PrePaid`. Value range [1, 12]. -* `zone_id` - (Optional) Selected zone to create database instance. You cannot set the ZoneId parameter if the MultiAZ parameter is set to true. -* `multi_az` - (Optional) Specifies if the database instance is a multiple Availability Zone deployment. -* `db_instance_net_type` - (Optional) Network connection type of an instance. Internet: public network; Intranet: private network -* `allocate_public_connection` - (Optional) If set to true will applies for an Internet connection string of an instance. -* `instance_network_type` - (Optional) VPC: VPC instance; Classic: classic instance. If no value is specified, a classic instance will be created by default. -* `vswitch_id` - (Optional) The virtual switch ID to launch in VPC. If you want to create instances in VPC network, this parameter must be set. -* `master_user_name` - (Optional) The master user name for the database instance. Operation account requiring a uniqueness check. It may consist of lower case letters, numbers and underlines, and must start with a letter and have no more than 16 characters. -* `master_user_password` - (Optional) The master password for the database instance. Operation password. It may consist of letters, digits, or underlines, with a length of 6 to 32 characters. -* `preferred_backup_period` - (Optional) Backup period. Values: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, and Sunday. -* `preferred_backup_time` - (Optional) Backup time, in the format ofHH:mmZ- HH:mm Z. -* `backup_retention_period` - (Optional) Retention days of the backup (7 to 730 days). The default value is 7 days. -* `security_ips` - (Optional) List of IP addresses under the IP address white list array. The list contains up to 1,000 IP addresses, separated by commas. Supported formats include 0.0.0.0/0, 10.23.12.24 (IP), and 10.23.12.24/24 (Classless Inter-Domain Routing (CIDR) mode. /24 represents the length of the prefix in an IP address. The range of the prefix length is [1,32]). -* `db_mappings` - (Optional) Database mappings to attach to db instance. See [Block database](#block-database) below for details. - - -## Block database - -The database mapping supports the following: - -* `db_name` - (Required) Name of the database requiring a uniqueness check. It may consist of lower case letters, numbers and underlines, and must start with a letter and have no more than 64 characters. -* `character_set_name` - (Required) Character set. The value range is limited to the following: - - MySQL type: - + utf8 - + gbk - + latin1 - + utf8mb4 (included in versions 5.5 and 5.6). - - SQLServer type: - + Chinese_PRC_CI_AS - + Chinese_PRC_CS_AS - + SQL_Latin1_General_CP1_CI_AS - + SQL_Latin1_General_CP1_CS_AS - + Chinese_PRC_BIN -* `db_description` - (Optional) Database description, which cannot exceed 256 characters. NOTE: It cannot begin with https://. - - -~> **NOTE:** We neither support modify any of database attribute, nor insert/remove item at the same time. -We recommend split to two separate operations. + Increase progressively at a rate of 5 GB. For details, see [Instance type table](https://www.alibabacloud.com/help/doc-detail/26312.htm). + +* `instance_charge_type` - (Optional) Valid values are `Prepaid`, `Postpaid`, Default to `Postpaid`. +* `period` - (Optional) The duration that you will buy DB instance (in month). It is valid when instance_charge_type is `PrePaid`. Valid values: [1~9], 12, 24, 36. Default to 1. +* `zone_id` - (Optional) The Zone to launch the DB instance. It is ignored and will be computed when set `vswitch_id`. It conflict with `multi_az`. +* `multi_az` - (Optional) Whether to use multiple availability zone in specified region. It conflict with `zone_id`. +* `db_instance_net_type` - (Deprecated) It has been deprecated from version 1.5.0. If you want to set public connection, please use new resource `alicloud_db_connection`. Default to Intranet. +* `allocate_public_connection` - (Deprecated) It has been deprecated from version 1.5.0. If you want to allocate public connection string, please use new resource `alicloud_db_connection`. +* `instance_network_type` - (Deprecated) It has been deprecated from version 1.5.0. If you want to create instances in VPC network, this parameter must be set. +* `vswitch_id` - (Optional) The virtual switch ID to launch DB instances in one VPC. +* `master_user_name` - (Deprecated) It has been deprecated from version 1.5.0. New resource `alicloud_db_account` field 'name' replaces it. +* `master_user_password` - (Deprecated) It has been deprecated from version 1.5.0. New resource `alicloud_db_account` field 'password' replaces it. +* `preferred_backup_period` - (Deprecated) It has been deprecated from version 1.5.0. New resource `alicloud_db_backup_policy` field 'backup_period' replaces it. +* `preferred_backup_time` - (Deprecated) It has been deprecated from version 1.5.0. New resource `alicloud_db_backup_policy` field 'backup_time' replaces it. +* `backup_retention_period` - (Deprecated) It has been deprecated from version 1.5.0. New resource `alicloud_db_backup_policy` field 'retention_period' replaces it. +* `security_ips` - (Optional) List of IP addresses allowed to access all databases of an instance. The list contains up to 1,000 IP addresses, separated by commas. Supported formats include 0.0.0.0/0, 10.23.12.24 (IP), and 10.23.12.24/24 (Classless Inter-Domain Routing (CIDR) mode. /24 represents the length of the prefix in an IP address. The range of the prefix length is [1,32]). +* `db_mappings` - (Deprecated) It has been deprecated from version 1.5.0. New resource `alicloud_db_database` replaces it. + +~> **NOTE:** Because of data backup and migration, change DB instance type and storage would cost 15~20 minutes. Please make full preparation before changing them. ## Attributes Reference @@ -88,24 +67,27 @@ The following attributes are exported: * `id` - The RDS instance ID. * `instance_charge_type` - The instance charge type. -* `period` - The time that you have bought the resource. +* `period` - The DB instance using duration. * `engine` - Database type. * `engine_version` - The database engine version. -* `db_instance_class` - The RDS instance class. -* `db_instance_storage` - The amount of allocated storage. -* `port` - The database port. -* `zone_id` - The zone ID of the DB instance. -* `db_instance_net_type` - Network connection type of an instance, `Internet` or `Intranet`. -* `instance_network_type` - The instance network type and it has two values: `vpc` and `classic`. -* `db_mappings` - Database mappings attached to db instance. -* `preferred_backup_period` - Backup period. -* `preferred_backup_time` - Backup time. -* `backup_retention_period` - Retention days of the backup. +* `db_instance_class` - (Deprecated from version 1.5.0) +* `instance_type` - The RDS instance type. +* `db_instance_storage` - (Deprecated from version 1.5.0) +* `instance_storage` - The RDS instance storage space. +* `port` - RDS database connection port. +* `connection_string` - RDS database connection string. +* `zone_id` - The zone ID of the RDS instance. +* `db_instance_net_type` - (Deprecated from version 1.5.0). +* `instance_network_type` - (Deprecated from version 1.5.0). +* `db_mappings` - - (Deprecated from version 1.5.0). +* `preferred_backup_period` - (Deprecated from version 1.5.0). +* `preferred_backup_time` - (Deprecated from version 1.5.0). +* `backup_retention_period` - (Deprecated from version 1.5.0). * `security_ips` - Security ips of instance whitelist. -* `connections` - Views all the connection information of a specified instance. +* `connections` - (Deprecated from version 1.5.0). * `vswitch_id` - If the rds instance created in VPC, then this value is virtual switch ID. -* `master_user_name` - The master user name of the database instance. -* `preferred_backup_period` - Database backup period. -* `preferred_backup_time` - Database backup time, in the format ofHH:mmZ- HH:mm Z. -* `backup_retention_period` - Retention days of the backup. +* `master_user_name` - (Deprecated from version 1.5.0). +* `preferred_backup_period` - (Deprecated from version 1.5.0). +* `preferred_backup_time` - (Deprecated from version 1.5.0). +* `backup_retention_period` - (Deprecated from version 1.5.0).