From 69ec7e12ac6787c01ea78a65faec29e1720d894c Mon Sep 17 00:00:00 2001 From: demonwy Date: Tue, 18 Apr 2017 20:18:57 +0800 Subject: [PATCH] provider/alicloud: Add new resource ESS, including scalinggroup scalingconfiguration scalingrule and schedule (#13731) * add docs * add new resource ess * add examples * update aliyun go * merge master * fix ci --- builtin/providers/alicloud/common.go | 39 +- builtin/providers/alicloud/config.go | 13 + builtin/providers/alicloud/errors.go | 18 + builtin/providers/alicloud/provider.go | 22 +- .../alicloud/resource_alicloud_db_instance.go | 7 +- .../resource_alicloud_db_instance_test.go | 2 +- .../alicloud/resource_alicloud_eip.go | 15 +- .../resource_alicloud_eip_association.go | 2 +- ...ource_alicloud_ess_scalingconfiguration.go | 320 +++++++++++ ..._alicloud_ess_scalingconfiguration_test.go | 495 ++++++++++++++++++ .../resource_alicloud_ess_scalinggroup.go | 209 ++++++++ ...resource_alicloud_ess_scalinggroup_test.go | 297 +++++++++++ .../resource_alicloud_ess_scalingrule.go | 168 ++++++ .../resource_alicloud_ess_scalingrule_test.go | 290 ++++++++++ .../resource_alicloud_ess_schedule.go | 220 ++++++++ .../resource_alicloud_ess_schedule_test.go | 151 ++++++ .../alicloud/resource_alicloud_forward.go | 165 ++++++ .../resource_alicloud_forward_test.go | 216 ++++++++ .../alicloud/resource_alicloud_instance.go | 81 +-- .../alicloud/resource_alicloud_nat_gateway.go | 93 +++- .../resource_alicloud_nat_gateway_test.go | 42 +- .../resource_alicloud_security_group.go | 5 + .../resource_alicloud_security_group_rule.go | 31 +- .../alicloud/resource_alicloud_slb.go | 5 + .../resource_alicloud_slb_attachment.go | 8 +- .../alicloud/resource_alicloud_snat.go | 134 +++++ .../alicloud/resource_alicloud_snat_test.go | 180 +++++++ .../alicloud/resource_alicloud_vpc.go | 4 +- .../alicloud/resource_alicloud_vswitch.go | 4 +- .../alicloud/service_alicloud_ecs.go | 4 +- .../alicloud/service_alicloud_ess.go | 167 ++++++ .../alicloud/service_alicloud_rds.go | 28 +- .../alicloud/service_alicloud_vpc.go | 75 ++- .../alicloud/struct_security_groups.go | 11 - builtin/providers/alicloud/validators.go | 21 +- builtin/providers/alicloud/validators_test.go | 14 +- examples/alicloud-ess-scaling/README.md | 17 + examples/alicloud-ess-scaling/main.tf | 38 ++ examples/alicloud-ess-scaling/outputs.tf | 7 + examples/alicloud-ess-scaling/variables.tf | 24 + examples/alicloud-ess-schedule/README.md | 17 + examples/alicloud-ess-schedule/main.tf | 51 ++ examples/alicloud-ess-schedule/outputs.tf | 11 + examples/alicloud-ess-schedule/variables.tf | 32 ++ examples/alicloud-vpc-snat/main.tf | 87 +++ examples/alicloud-vpc-snat/ouputs.tf | 7 + examples/alicloud-vpc-snat/variables.tf | 22 + .../denverdino/aliyungo/common/client.go | 77 +++ .../denverdino/aliyungo/common/endpoints.xml | 68 ++- .../denverdino/aliyungo/ecs/forward_entry.go | 104 ++++ .../denverdino/aliyungo/ecs/vpcs.go | 1 + .../denverdino/aliyungo/ecs/vswitches.go | 1 + .../denverdino/aliyungo/ess/client.go | 48 ++ .../denverdino/aliyungo/ess/configuration.go | 127 +++++ .../denverdino/aliyungo/ess/group.go | 242 +++++++++ .../denverdino/aliyungo/ess/rule.go | 130 +++++ .../denverdino/aliyungo/ess/schedule.go | 140 +++++ .../denverdino/aliyungo/util/encoding.go | 162 ++++++ vendor/vendor.json | 32 +- .../alicloud/r/db_instance.html.markdown | 27 +- .../providers/alicloud/r/disk.html.markdown | 12 +- .../alicloud/r/disk_attachment.html.markdown | 8 +- .../providers/alicloud/r/eip.html.markdown | 6 +- .../alicloud/r/eip_association.html.markdown | 8 +- .../r/ess_scaling_configuration.html.markdown | 84 +++ .../r/ess_scaling_group.html.markdown | 57 ++ .../alicloud/r/ess_scaling_rule.html.markdown | 59 +++ .../alicloud/r/ess_schedule.html.markdown | 65 +++ .../alicloud/r/forward.html.markdown | 68 +++ .../alicloud/r/instance.html.markdown | 21 +- .../alicloud/r/nat_gateway.html.markdown | 23 +- .../alicloud/r/security_group.html.markdown | 11 +- .../r/security_group_rule.html.markdown | 6 +- .../providers/alicloud/r/slb.html.markdown | 61 ++- .../alicloud/r/slb_attachment.html.markdown | 8 +- .../providers/alicloud/r/snat.html.markdown | 61 +++ .../providers/alicloud/r/vpc.html.markdown | 3 +- .../alicloud/r/vroute_entry.html.markdown | 4 +- .../alicloud/r/vswitch.html.markdown | 4 +- website/source/layouts/alicloud.erb | 181 ++++--- 80 files changed, 5475 insertions(+), 303 deletions(-) create mode 100644 builtin/providers/alicloud/resource_alicloud_ess_scalingconfiguration.go create mode 100644 builtin/providers/alicloud/resource_alicloud_ess_scalingconfiguration_test.go create mode 100644 builtin/providers/alicloud/resource_alicloud_ess_scalinggroup.go create mode 100644 builtin/providers/alicloud/resource_alicloud_ess_scalinggroup_test.go create mode 100644 builtin/providers/alicloud/resource_alicloud_ess_scalingrule.go create mode 100644 builtin/providers/alicloud/resource_alicloud_ess_scalingrule_test.go create mode 100644 builtin/providers/alicloud/resource_alicloud_ess_schedule.go create mode 100644 builtin/providers/alicloud/resource_alicloud_ess_schedule_test.go create mode 100644 builtin/providers/alicloud/resource_alicloud_forward.go create mode 100644 builtin/providers/alicloud/resource_alicloud_forward_test.go create mode 100644 builtin/providers/alicloud/resource_alicloud_snat.go create mode 100644 builtin/providers/alicloud/resource_alicloud_snat_test.go create mode 100644 builtin/providers/alicloud/service_alicloud_ess.go delete mode 100644 builtin/providers/alicloud/struct_security_groups.go create mode 100644 examples/alicloud-ess-scaling/README.md create mode 100644 examples/alicloud-ess-scaling/main.tf create mode 100644 examples/alicloud-ess-scaling/outputs.tf create mode 100644 examples/alicloud-ess-scaling/variables.tf create mode 100644 examples/alicloud-ess-schedule/README.md create mode 100644 examples/alicloud-ess-schedule/main.tf create mode 100644 examples/alicloud-ess-schedule/outputs.tf create mode 100644 examples/alicloud-ess-schedule/variables.tf create mode 100644 examples/alicloud-vpc-snat/main.tf create mode 100644 examples/alicloud-vpc-snat/ouputs.tf create mode 100644 examples/alicloud-vpc-snat/variables.tf create mode 100644 vendor/github.com/denverdino/aliyungo/ecs/forward_entry.go create mode 100644 vendor/github.com/denverdino/aliyungo/ess/client.go create mode 100644 vendor/github.com/denverdino/aliyungo/ess/configuration.go create mode 100644 vendor/github.com/denverdino/aliyungo/ess/group.go create mode 100644 vendor/github.com/denverdino/aliyungo/ess/rule.go create mode 100644 vendor/github.com/denverdino/aliyungo/ess/schedule.go create mode 100644 website/source/docs/providers/alicloud/r/ess_scaling_configuration.html.markdown create mode 100644 website/source/docs/providers/alicloud/r/ess_scaling_group.html.markdown create mode 100644 website/source/docs/providers/alicloud/r/ess_scaling_rule.html.markdown create mode 100644 website/source/docs/providers/alicloud/r/ess_schedule.html.markdown create mode 100644 website/source/docs/providers/alicloud/r/forward.html.markdown create mode 100644 website/source/docs/providers/alicloud/r/snat.html.markdown diff --git a/builtin/providers/alicloud/common.go b/builtin/providers/alicloud/common.go index c2af2a683..e9bb1a9f8 100644 --- a/builtin/providers/alicloud/common.go +++ b/builtin/providers/alicloud/common.go @@ -17,38 +17,39 @@ const ( const defaultTimeout = 120 // timeout for long time progerss product, rds e.g. -const defaultLongTimeout = 800 +const defaultLongTimeout = 1000 func getRegion(d *schema.ResourceData, meta interface{}) common.Region { return meta.(*AliyunClient).Region } func notFoundError(err error) bool { - if e, ok := err.(*common.Error); ok && (e.StatusCode == 404 || e.ErrorResponse.Message == "Not found") { + if e, ok := err.(*common.Error); ok && + (e.StatusCode == 404 || e.ErrorResponse.Message == "Not found" || e.Code == InstanceNotfound) { return true } return false } -// Protocal represents network protocal -type Protocal string +// Protocol represents network protocol +type Protocol string -// Constants of protocal definition +// Constants of protocol definition const ( - Http = Protocal("http") - Https = Protocal("https") - Tcp = Protocal("tcp") - Udp = Protocal("udp") + Http = Protocol("http") + Https = Protocol("https") + Tcp = Protocol("tcp") + Udp = Protocol("udp") ) -// ValidProtocals network protocal list -var ValidProtocals = []Protocal{Http, Https, Tcp, Udp} +// ValidProtocols network protocol list +var ValidProtocols = []Protocol{Http, Https, Tcp, Udp} // simple array value check method, support string type only -func isProtocalValid(value string) bool { +func isProtocolValid(value string) bool { res := false - for _, v := range ValidProtocals { + for _, v := range ValidProtocols { if string(v) == value { res = true } @@ -77,4 +78,16 @@ const DB_DEFAULT_CONNECT_PORT = "3306" const COMMA_SEPARATED = "," +const COLON_SEPARATED = ":" + const LOCAL_HOST_IP = "127.0.0.1" + +// Takes the result of flatmap.Expand for an array of strings +// and returns a []string +func expandStringList(configured []interface{}) []string { + vs := make([]string, 0, len(configured)) + for _, v := range configured { + vs = append(vs, v.(string)) + } + return vs +} diff --git a/builtin/providers/alicloud/config.go b/builtin/providers/alicloud/config.go index e17003bb2..f84c7e02a 100644 --- a/builtin/providers/alicloud/config.go +++ b/builtin/providers/alicloud/config.go @@ -5,6 +5,7 @@ import ( "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/ecs" + "github.com/denverdino/aliyungo/ess" "github.com/denverdino/aliyungo/rds" "github.com/denverdino/aliyungo/slb" ) @@ -20,6 +21,7 @@ type Config struct { type AliyunClient struct { Region common.Region ecsconn *ecs.Client + essconn *ess.Client rdsconn *rds.Client // use new version ecsNewconn *ecs.Client @@ -60,6 +62,11 @@ func (c *Config) Client() (*AliyunClient, error) { return nil, err } + essconn, err := c.essConn() + if err != nil { + return nil, err + } + return &AliyunClient{ Region: c.Region, ecsconn: ecsconn, @@ -67,6 +74,7 @@ func (c *Config) Client() (*AliyunClient, error) { vpcconn: vpcconn, slbconn: slbconn, rdsconn: rdsconn, + essconn: essconn, }, nil } @@ -123,3 +131,8 @@ func (c *Config) vpcConn() (*ecs.Client, error) { return client, nil } +func (c *Config) essConn() (*ess.Client, error) { + client := ess.NewESSClient(c.AccessKey, c.SecretKey, c.Region) + client.SetBusinessInfo(BusinessInfoKey) + return client, nil +} diff --git a/builtin/providers/alicloud/errors.go b/builtin/providers/alicloud/errors.go index 338525330..06d29642b 100644 --- a/builtin/providers/alicloud/errors.go +++ b/builtin/providers/alicloud/errors.go @@ -1,5 +1,7 @@ package alicloud +import "github.com/denverdino/aliyungo/common" + const ( // common Notfound = "Not found" @@ -25,7 +27,23 @@ const ( //Nat gateway NatGatewayInvalidRegionId = "Invalid.RegionId" DependencyViolationBandwidthPackages = "DependencyViolation.BandwidthPackages" + NotFindSnatEntryBySnatId = "NotFindSnatEntryBySnatId" + NotFindForwardEntryByForwardId = "NotFindForwardEntryByForwardId" // vswitch VswitcInvalidRegionId = "InvalidRegionId.NotFound" + + // ess + InvalidScalingGroupIdNotFound = "InvalidScalingGroupId.NotFound" + IncorrectScalingConfigurationLifecycleState = "IncorrectScalingConfigurationLifecycleState" ) + +func GetNotFoundErrorFromString(str string) error { + return &common.Error{ + ErrorResponse: common.ErrorResponse{ + Code: InstanceNotfound, + Message: str, + }, + StatusCode: -1, + } +} diff --git a/builtin/providers/alicloud/provider.go b/builtin/providers/alicloud/provider.go index 677c1c70d..fe3613014 100644 --- a/builtin/providers/alicloud/provider.go +++ b/builtin/providers/alicloud/provider.go @@ -38,18 +38,24 @@ func Provider() terraform.ResourceProvider { "alicloud_instance_types": dataSourceAlicloudInstanceTypes(), }, ResourcesMap: map[string]*schema.Resource{ - "alicloud_instance": resourceAliyunInstance(), - "alicloud_disk": resourceAliyunDisk(), - "alicloud_disk_attachment": resourceAliyunDiskAttachment(), - "alicloud_security_group": resourceAliyunSecurityGroup(), - "alicloud_security_group_rule": resourceAliyunSecurityGroupRule(), - "alicloud_db_instance": resourceAlicloudDBInstance(), - "alicloud_vpc": resourceAliyunVpc(), - "alicloud_nat_gateway": resourceAliyunNatGateway(), + "alicloud_instance": resourceAliyunInstance(), + "alicloud_disk": resourceAliyunDisk(), + "alicloud_disk_attachment": resourceAliyunDiskAttachment(), + "alicloud_security_group": resourceAliyunSecurityGroup(), + "alicloud_security_group_rule": resourceAliyunSecurityGroupRule(), + "alicloud_db_instance": resourceAlicloudDBInstance(), + "alicloud_ess_scaling_group": resourceAlicloudEssScalingGroup(), + "alicloud_ess_scaling_configuration": resourceAlicloudEssScalingConfiguration(), + "alicloud_ess_scaling_rule": resourceAlicloudEssScalingRule(), + "alicloud_ess_schedule": resourceAlicloudEssSchedule(), + "alicloud_vpc": resourceAliyunVpc(), + "alicloud_nat_gateway": resourceAliyunNatGateway(), //both subnet and vswith exists,cause compatible old version, and compatible aws habit. "alicloud_subnet": resourceAliyunSubnet(), "alicloud_vswitch": resourceAliyunSubnet(), "alicloud_route_entry": resourceAliyunRouteEntry(), + "alicloud_snat_entry": resourceAliyunSnatEntry(), + "alicloud_forward_entry": resourceAliyunForwardEntry(), "alicloud_eip": resourceAliyunEip(), "alicloud_eip_association": resourceAliyunEipAssociation(), "alicloud_slb": resourceAliyunSlb(), diff --git a/builtin/providers/alicloud/resource_alicloud_db_instance.go b/builtin/providers/alicloud/resource_alicloud_db_instance.go index c19aef165..062b5d0e1 100644 --- a/builtin/providers/alicloud/resource_alicloud_db_instance.go +++ b/builtin/providers/alicloud/resource_alicloud_db_instance.go @@ -218,7 +218,7 @@ func resourceAlicloudDBInstanceCreate(d *schema.ResourceData, meta interface{}) // wait instance status change from Creating to running if err := conn.WaitForInstance(d.Id(), rds.Running, defaultLongTimeout); err != nil { - log.Printf("[DEBUG] WaitForInstance %s got error: %#v", rds.Running, err) + return fmt.Errorf("WaitForInstance %s got error: %#v", rds.Running, err) } if err := modifySecurityIps(d.Id(), d.Get("security_ips"), meta); err != nil { @@ -386,6 +386,11 @@ func resourceAlicloudDBInstanceRead(d *schema.ResourceData, meta interface{}) er 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{ diff --git a/builtin/providers/alicloud/resource_alicloud_db_instance_test.go b/builtin/providers/alicloud/resource_alicloud_db_instance_test.go index 8348e5089..498cc3ae1 100644 --- a/builtin/providers/alicloud/resource_alicloud_db_instance_test.go +++ b/builtin/providers/alicloud/resource_alicloud_db_instance_test.go @@ -535,7 +535,7 @@ func testAccCheckDBInstanceDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*AliyunClient) for _, rs := range s.RootModule().Resources { - if rs.Type != "alicloud_db_instance.foo" { + if rs.Type != "alicloud_db_instance" { continue } diff --git a/builtin/providers/alicloud/resource_alicloud_eip.go b/builtin/providers/alicloud/resource_alicloud_eip.go index 8a0329eb8..f1c9621a8 100644 --- a/builtin/providers/alicloud/resource_alicloud_eip.go +++ b/builtin/providers/alicloud/resource_alicloud_eip.go @@ -78,7 +78,14 @@ func resourceAliyunEipRead(d *schema.ResourceData, meta interface{}) error { d.SetId("") return nil } - return err + return fmt.Errorf("Error Describe Eip Attribute: %#v", err) + } + + if eip.InstanceId != "" { + d.Set("instance", eip.InstanceId) + } else { + d.Set("instance", "") + return nil } bandwidth, _ := strconv.Atoi(eip.Bandwidth) @@ -87,12 +94,6 @@ func resourceAliyunEipRead(d *schema.ResourceData, meta interface{}) error { d.Set("ip_address", eip.IpAddress) d.Set("status", eip.Status) - if eip.InstanceId != "" { - d.Set("instance", eip.InstanceId) - } else { - d.Set("instance", "") - } - return nil } diff --git a/builtin/providers/alicloud/resource_alicloud_eip_association.go b/builtin/providers/alicloud/resource_alicloud_eip_association.go index a9d419ce1..5f492b40b 100644 --- a/builtin/providers/alicloud/resource_alicloud_eip_association.go +++ b/builtin/providers/alicloud/resource_alicloud_eip_association.go @@ -66,7 +66,7 @@ func resourceAliyunEipAssociationRead(d *schema.ResourceData, meta interface{}) d.SetId("") return nil } - return err + return fmt.Errorf("Error Describe Eip Attribute: %#v", err) } if eip.InstanceId != instanceId { diff --git a/builtin/providers/alicloud/resource_alicloud_ess_scalingconfiguration.go b/builtin/providers/alicloud/resource_alicloud_ess_scalingconfiguration.go new file mode 100644 index 000000000..3a8d94380 --- /dev/null +++ b/builtin/providers/alicloud/resource_alicloud_ess_scalingconfiguration.go @@ -0,0 +1,320 @@ +package alicloud + +import ( + "fmt" + "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ecs" + "github.com/denverdino/aliyungo/ess" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "strings" + "time" +) + +func resourceAlicloudEssScalingConfiguration() *schema.Resource { + return &schema.Resource{ + Create: resourceAliyunEssScalingConfigurationCreate, + Read: resourceAliyunEssScalingConfigurationRead, + Update: resourceAliyunEssScalingConfigurationUpdate, + Delete: resourceAliyunEssScalingConfigurationDelete, + + Schema: map[string]*schema.Schema{ + "active": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + "enable": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + }, + "scaling_group_id": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, + "image_id": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, + "instance_type": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, + "io_optimized": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateIoOptimized, + }, + "security_group_id": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, + "scaling_configuration_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "internet_charge_type": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Computed: true, + ValidateFunc: validateInternetChargeType, + }, + "internet_max_bandwidth_in": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Computed: true, + }, + "internet_max_bandwidth_out": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + ValidateFunc: validateInternetMaxBandWidthOut, + }, + "system_disk_category": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ValidateFunc: validateAllowedStringValue([]string{ + string(ecs.DiskCategoryCloud), + string(ecs.DiskCategoryCloudSSD), + string(ecs.DiskCategoryCloudEfficiency), + string(ecs.DiskCategoryEphemeralSSD), + }), + }, + "data_disk": &schema.Schema{ + Optional: true, + ForceNew: true, + Type: schema.TypeList, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + }, + "category": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "snapshot_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "device": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "instance_ids": &schema.Schema{ + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + MaxItems: 20, + }, + }, + } +} + +func resourceAliyunEssScalingConfigurationCreate(d *schema.ResourceData, meta interface{}) error { + + args, err := buildAlicloudEssScalingConfigurationArgs(d, meta) + if err != nil { + return err + } + + essconn := meta.(*AliyunClient).essconn + + scaling, err := essconn.CreateScalingConfiguration(args) + if err != nil { + return err + } + + d.SetId(d.Get("scaling_group_id").(string) + COLON_SEPARATED + scaling.ScalingConfigurationId) + + return resourceAliyunEssScalingConfigurationUpdate(d, meta) +} + +func resourceAliyunEssScalingConfigurationUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AliyunClient) + if d.HasChange("active") { + active := d.Get("active").(bool) + if !active { + return fmt.Errorf("Please active the scaling configuration directly.") + } + ids := strings.Split(d.Id(), COLON_SEPARATED) + err := client.ActiveScalingConfigurationById(ids[0], ids[1]) + + if err != nil { + return fmt.Errorf("Active scaling configuration %s err: %#v", ids[1], err) + } + } + + if err := enableEssScalingConfiguration(d, meta); err != nil { + return err + } + + return resourceAliyunEssScalingConfigurationRead(d, meta) +} + +func enableEssScalingConfiguration(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AliyunClient) + ids := strings.Split(d.Id(), COLON_SEPARATED) + + if d.HasChange("enable") { + d.SetPartial("enable") + enable := d.Get("enable").(bool) + if !enable { + err := client.DisableScalingConfigurationById(ids[0]) + + if err != nil { + return fmt.Errorf("Disable scaling group %s err: %#v", ids[0], err) + } + } + + instance_ids := []string{} + if d.HasChange("instance_ids") { + d.SetPartial("instance_ids") + instances := d.Get("instance_ids").([]interface{}) + instance_ids = expandStringList(instances) + } + err := client.EnableScalingConfigurationById(ids[0], ids[1], instance_ids) + + if err != nil { + return fmt.Errorf("Enable scaling configuration %s err: %#v", ids[1], err) + } + } + return nil +} + +func resourceAliyunEssScalingConfigurationRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*AliyunClient) + ids := strings.Split(d.Id(), COLON_SEPARATED) + c, err := client.DescribeScalingConfigurationById(ids[0], ids[1]) + if err != nil { + if e, ok := err.(*common.Error); ok && e.Code == InstanceNotfound { + d.SetId("") + return nil + } + return fmt.Errorf("Error Describe ESS scaling configuration Attribute: %#v", err) + } + + d.Set("scaling_group_id", c.ScalingGroupId) + d.Set("active", c.LifecycleState == ess.Active) + d.Set("image_id", c.ImageId) + d.Set("instance_type", c.InstanceType) + d.Set("io_optimized", c.IoOptimized) + d.Set("security_group_id", c.SecurityGroupId) + d.Set("scaling_configuration_name", c.ScalingConfigurationName) + d.Set("internet_charge_type", c.InternetChargeType) + d.Set("internet_max_bandwidth_in", c.InternetMaxBandwidthIn) + d.Set("internet_max_bandwidth_out", c.InternetMaxBandwidthOut) + d.Set("system_disk_category", c.SystemDiskCategory) + d.Set("data_disk", flattenDataDiskMappings(c.DataDisks.DataDisk)) + + return nil +} + +func resourceAliyunEssScalingConfigurationDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AliyunClient) + + return resource.Retry(5*time.Minute, func() *resource.RetryError { + ids := strings.Split(d.Id(), COLON_SEPARATED) + err := client.DeleteScalingConfigurationById(ids[0], ids[1]) + + if err != nil { + e, _ := err.(*common.Error) + if e.ErrorResponse.Code == IncorrectScalingConfigurationLifecycleState { + return resource.NonRetryableError( + fmt.Errorf("Scaling configuration is active - please active another one and trying again.")) + } + if e.ErrorResponse.Code != InvalidScalingGroupIdNotFound { + return resource.RetryableError( + fmt.Errorf("Scaling configuration in use - trying again while it is deleted.")) + } + } + + _, err = client.DescribeScalingConfigurationById(ids[0], ids[1]) + if err != nil { + if notFoundError(err) { + return nil + } + return resource.NonRetryableError(err) + } + + return resource.RetryableError( + fmt.Errorf("Scaling configuration in use - trying again while it is deleted.")) + }) +} + +func buildAlicloudEssScalingConfigurationArgs(d *schema.ResourceData, meta interface{}) (*ess.CreateScalingConfigurationArgs, error) { + args := &ess.CreateScalingConfigurationArgs{ + ScalingGroupId: d.Get("scaling_group_id").(string), + ImageId: d.Get("image_id").(string), + InstanceType: d.Get("instance_type").(string), + IoOptimized: ecs.IoOptimized(d.Get("io_optimized").(string)), + SecurityGroupId: d.Get("security_group_id").(string), + } + + if v := d.Get("scaling_configuration_name").(string); v != "" { + args.ScalingConfigurationName = v + } + + if v := d.Get("internet_charge_type").(string); v != "" { + args.InternetChargeType = common.InternetChargeType(v) + } + + if v := d.Get("internet_max_bandwidth_in").(int); v != 0 { + args.InternetMaxBandwidthIn = v + } + + if v := d.Get("internet_max_bandwidth_out").(int); v != 0 { + args.InternetMaxBandwidthOut = v + } + + if v := d.Get("system_disk_category").(string); v != "" { + args.SystemDisk_Category = common.UnderlineString(v) + } + + dds, ok := d.GetOk("data_disk") + if ok { + disks := dds.([]interface{}) + diskTypes := []ess.DataDiskType{} + + for _, e := range disks { + pack := e.(map[string]interface{}) + disk := ess.DataDiskType{ + Size: pack["size"].(int), + Category: pack["category"].(string), + SnapshotId: pack["snapshot_id"].(string), + Device: pack["device"].(string), + } + if v := pack["size"].(int); v != 0 { + disk.Size = v + } + if v := pack["category"].(string); v != "" { + disk.Category = v + } + if v := pack["snapshot_id"].(string); v != "" { + disk.SnapshotId = v + } + if v := pack["device"].(string); v != "" { + disk.Device = v + } + diskTypes = append(diskTypes, disk) + } + args.DataDisk = diskTypes + } + + return args, nil +} diff --git a/builtin/providers/alicloud/resource_alicloud_ess_scalingconfiguration_test.go b/builtin/providers/alicloud/resource_alicloud_ess_scalingconfiguration_test.go new file mode 100644 index 000000000..4a2269b38 --- /dev/null +++ b/builtin/providers/alicloud/resource_alicloud_ess_scalingconfiguration_test.go @@ -0,0 +1,495 @@ +package alicloud + +import ( + "fmt" + "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ess" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "log" + "regexp" + "strings" + "testing" +) + +func TestAccAlicloudEssScalingConfiguration_basic(t *testing.T) { + var sc ess.ScalingConfigurationItemType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_ess_scaling_configuration.foo", + + Providers: testAccProviders, + CheckDestroy: testAccCheckEssScalingConfigurationDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccEssScalingConfigurationConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingConfigurationExists( + "alicloud_ess_scaling_configuration.foo", &sc), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_configuration.foo", + "instance_type", + "ecs.s2.large"), + resource.TestMatchResourceAttr( + "alicloud_ess_scaling_configuration.foo", + "image_id", + regexp.MustCompile("^centos_6")), + ), + }, + }, + }) +} + +func TestAccAlicloudEssScalingConfiguration_multiConfig(t *testing.T) { + var sc ess.ScalingConfigurationItemType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_ess_scaling_configuration.bar", + + Providers: testAccProviders, + CheckDestroy: testAccCheckEssScalingConfigurationDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccEssScalingConfiguration_multiConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingConfigurationExists( + "alicloud_ess_scaling_configuration.bar", &sc), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_configuration.bar", + "active", + "false"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_configuration.bar", + "instance_type", + "ecs.s2.large"), + resource.TestMatchResourceAttr( + "alicloud_ess_scaling_configuration.bar", + "image_id", + regexp.MustCompile("^centos_6")), + ), + }, + }, + }) +} + +func SkipTestAccAlicloudEssScalingConfiguration_active(t *testing.T) { + var sc ess.ScalingConfigurationItemType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_ess_scaling_configuration.bar", + + Providers: testAccProviders, + CheckDestroy: testAccCheckEssScalingConfigurationDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccEssScalingConfiguration_active, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingConfigurationExists( + "alicloud_ess_scaling_configuration.bar", &sc), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_configuration.bar", + "active", + "true"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_configuration.bar", + "instance_type", + "ecs.s2.large"), + resource.TestMatchResourceAttr( + "alicloud_ess_scaling_configuration.bar", + "image_id", + regexp.MustCompile("^centos_6")), + ), + }, + + resource.TestStep{ + Config: testAccEssScalingConfiguration_inActive, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingConfigurationExists( + "alicloud_ess_scaling_configuration.bar", &sc), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_configuration.bar", + "active", + "false"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_configuration.bar", + "instance_type", + "ecs.s2.large"), + resource.TestMatchResourceAttr( + "alicloud_ess_scaling_configuration.bar", + "image_id", + regexp.MustCompile("^centos_6")), + ), + }, + }, + }) +} + +func SkipTestAccAlicloudEssScalingConfiguration_enable(t *testing.T) { + var sc ess.ScalingConfigurationItemType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_ess_scaling_configuration.foo", + + Providers: testAccProviders, + CheckDestroy: testAccCheckEssScalingConfigurationDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccEssScalingConfiguration_enable, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingConfigurationExists( + "alicloud_ess_scaling_configuration.foo", &sc), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_configuration.foo", + "enable", + "true"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_configuration.foo", + "instance_type", + "ecs.s2.large"), + resource.TestMatchResourceAttr( + "alicloud_ess_scaling_configuration.foo", + "image_id", + regexp.MustCompile("^centos_6")), + ), + }, + + resource.TestStep{ + Config: testAccEssScalingConfiguration_disable, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingConfigurationExists( + "alicloud_ess_scaling_configuration.foo", &sc), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_configuration.foo", + "enable", + "false"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_configuration.foo", + "instance_type", + "ecs.s2.large"), + resource.TestMatchResourceAttr( + "alicloud_ess_scaling_configuration.foo", + "image_id", + regexp.MustCompile("^centos_6")), + ), + }, + }, + }) +} + +func testAccCheckEssScalingConfigurationExists(n string, d *ess.ScalingConfigurationItemType) 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 ESS Scaling Configuration ID is set") + } + + client := testAccProvider.Meta().(*AliyunClient) + ids := strings.Split(rs.Primary.ID, COLON_SEPARATED) + attr, err := client.DescribeScalingConfigurationById(ids[0], ids[1]) + log.Printf("[DEBUG] check scaling configuration %s attribute %#v", rs.Primary.ID, attr) + + if err != nil { + return err + } + + if attr == nil { + return fmt.Errorf("Scaling Configuration not found") + } + + *d = *attr + return nil + } +} + +func testAccCheckEssScalingConfigurationDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*AliyunClient) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "alicloud_ess_scaling_configuration" { + continue + } + ids := strings.Split(rs.Primary.ID, COLON_SEPARATED) + ins, err := client.DescribeScalingConfigurationById(ids[0], ids[1]) + + if ins != nil { + return fmt.Errorf("Error ESS scaling configuration still exist") + } + + // Verify the error is what we want + if err != nil { + // Verify the error is what we want + e, _ := err.(*common.Error) + if e.ErrorResponse.Code == InstanceNotfound { + continue + } + return err + } + } + + return nil +} + +const testAccEssScalingConfigurationConfig = ` +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} + +resource "alicloud_security_group" "tf_test_foo" { + description = "foo" +} + +resource "alicloud_security_group_rule" "ssh-in" { + type = "ingress" + ip_protocol = "tcp" + nic_type = "internet" + policy = "accept" + port_range = "22/22" + priority = 1 + security_group_id = "${alicloud_security_group.tf_test_foo.id}" + cidr_ip = "0.0.0.0/0" +} + +resource "alicloud_ess_scaling_group" "foo" { + min_size = 1 + max_size = 1 + scaling_group_name = "foo" + removal_policies = ["OldestInstance", "NewestInstance"] +} + +resource "alicloud_ess_scaling_configuration" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.foo.id}" + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.s2.large" + io_optimized = "optimized" + security_group_id = "${alicloud_security_group.tf_test_foo.id}" +} +` + +const testAccEssScalingConfiguration_multiConfig = ` +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} + +resource "alicloud_security_group" "tf_test_foo" { + description = "foo" +} + +resource "alicloud_security_group_rule" "ssh-in" { + type = "ingress" + ip_protocol = "tcp" + nic_type = "internet" + policy = "accept" + port_range = "22/22" + priority = 1 + security_group_id = "${alicloud_security_group.tf_test_foo.id}" + cidr_ip = "0.0.0.0/0" +} + +resource "alicloud_ess_scaling_group" "foo" { + min_size = 1 + max_size = 1 + scaling_group_name = "foo" + removal_policies = ["OldestInstance", "NewestInstance"] +} + +resource "alicloud_ess_scaling_configuration" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.foo.id}" + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.s2.large" + io_optimized = "optimized" + security_group_id = "${alicloud_security_group.tf_test_foo.id}" +} + +resource "alicloud_ess_scaling_configuration" "bar" { + scaling_group_id = "${alicloud_ess_scaling_group.foo.id}" + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.s2.large" + io_optimized = "optimized" + security_group_id = "${alicloud_security_group.tf_test_foo.id}" +} +` + +const testAccEssScalingConfiguration_active = ` +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} + +resource "alicloud_security_group" "tf_test_foo" { + description = "foo" +} + +resource "alicloud_security_group_rule" "ssh-in" { + type = "ingress" + ip_protocol = "tcp" + nic_type = "internet" + policy = "accept" + port_range = "22/22" + priority = 1 + security_group_id = "${alicloud_security_group.tf_test_foo.id}" + cidr_ip = "0.0.0.0/0" +} + +resource "alicloud_ess_scaling_group" "foo" { + min_size = 1 + max_size = 1 + scaling_group_name = "foo" + removal_policies = ["OldestInstance", "NewestInstance"] +} + +resource "alicloud_ess_scaling_configuration" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.foo.id}" + active = true + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.s2.large" + io_optimized = "optimized" + security_group_id = "${alicloud_security_group.tf_test_foo.id}" +} +` + +const testAccEssScalingConfiguration_inActive = ` +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} + +resource "alicloud_security_group" "tf_test_foo" { + description = "foo" +} + +resource "alicloud_security_group_rule" "ssh-in" { + type = "ingress" + ip_protocol = "tcp" + nic_type = "internet" + policy = "accept" + port_range = "22/22" + priority = 1 + security_group_id = "${alicloud_security_group.tf_test_foo.id}" + cidr_ip = "0.0.0.0/0" +} + +resource "alicloud_ess_scaling_group" "foo" { + min_size = 1 + max_size = 1 + scaling_group_name = "foo" + removal_policies = ["OldestInstance", "NewestInstance"] +} + +resource "alicloud_ess_scaling_configuration" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.foo.id}" + active = false + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.s2.large" + io_optimized = "optimized" + security_group_id = "${alicloud_security_group.tf_test_foo.id}" +} +` + +const testAccEssScalingConfiguration_enable = ` +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} + +resource "alicloud_security_group" "tf_test_foo" { + description = "foo" +} + +resource "alicloud_security_group_rule" "ssh-in" { + type = "ingress" + ip_protocol = "tcp" + nic_type = "internet" + policy = "accept" + port_range = "22/22" + priority = 1 + security_group_id = "${alicloud_security_group.tf_test_foo.id}" + cidr_ip = "0.0.0.0/0" +} + +resource "alicloud_ess_scaling_group" "foo" { + min_size = 1 + max_size = 1 + scaling_group_name = "foo" + removal_policies = ["OldestInstance", "NewestInstance"] +} + +resource "alicloud_ess_scaling_configuration" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.foo.id}" + enable = true + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.s2.large" + io_optimized = "optimized" + security_group_id = "${alicloud_security_group.tf_test_foo.id}" +} +` + +const testAccEssScalingConfiguration_disable = ` +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} + +resource "alicloud_security_group" "tf_test_foo" { + description = "foo" +} + +resource "alicloud_security_group_rule" "ssh-in" { + type = "ingress" + ip_protocol = "tcp" + nic_type = "internet" + policy = "accept" + port_range = "22/22" + priority = 1 + security_group_id = "${alicloud_security_group.tf_test_foo.id}" + cidr_ip = "0.0.0.0/0" +} + +resource "alicloud_ess_scaling_group" "foo" { + min_size = 1 + max_size = 1 + scaling_group_name = "foo" + removal_policies = ["OldestInstance", "NewestInstance"] +} + +resource "alicloud_ess_scaling_configuration" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.foo.id}" + enable = false + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.s2.large" + io_optimized = "optimized" + security_group_id = "${alicloud_security_group.tf_test_foo.id}" +} +` diff --git a/builtin/providers/alicloud/resource_alicloud_ess_scalinggroup.go b/builtin/providers/alicloud/resource_alicloud_ess_scalinggroup.go new file mode 100644 index 000000000..89f4154db --- /dev/null +++ b/builtin/providers/alicloud/resource_alicloud_ess_scalinggroup.go @@ -0,0 +1,209 @@ +package alicloud + +import ( + "fmt" + "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ess" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "strings" + "time" +) + +func resourceAlicloudEssScalingGroup() *schema.Resource { + return &schema.Resource{ + Create: resourceAliyunEssScalingGroupCreate, + Read: resourceAliyunEssScalingGroupRead, + Update: resourceAliyunEssScalingGroupUpdate, + Delete: resourceAliyunEssScalingGroupDelete, + + Schema: map[string]*schema.Schema{ + "min_size": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ValidateFunc: validateIntegerInRange(0, 100), + }, + "max_size": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ValidateFunc: validateIntegerInRange(0, 100), + }, + "scaling_group_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "default_cooldown": &schema.Schema{ + Type: schema.TypeInt, + Default: 300, + Optional: true, + ValidateFunc: validateIntegerInRange(0, 86400), + }, + "vswitch_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "removal_policies": &schema.Schema{ + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + MaxItems: 2, + }, + "db_instance_ids": &schema.Schema{ + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + MaxItems: 3, + }, + "loadbalancer_ids": &schema.Schema{ + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + }, + }, + } +} + +func resourceAliyunEssScalingGroupCreate(d *schema.ResourceData, meta interface{}) error { + + args, err := buildAlicloudEssScalingGroupArgs(d, meta) + if err != nil { + return err + } + + essconn := meta.(*AliyunClient).essconn + + scaling, err := essconn.CreateScalingGroup(args) + if err != nil { + return err + } + + d.SetId(scaling.ScalingGroupId) + + return resourceAliyunEssScalingGroupUpdate(d, meta) +} + +func resourceAliyunEssScalingGroupRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*AliyunClient) + + scaling, err := client.DescribeScalingGroupById(d.Id()) + if err != nil { + if e, ok := err.(*common.Error); ok && e.Code == InstanceNotfound { + d.SetId("") + return nil + } + return fmt.Errorf("Error Describe ESS scaling group Attribute: %#v", err) + } + + d.Set("min_size", scaling.MinSize) + d.Set("max_size", scaling.MaxSize) + d.Set("scaling_group_name", scaling.ScalingGroupName) + d.Set("default_cooldown", scaling.DefaultCooldown) + d.Set("removal_policies", scaling.RemovalPolicies) + d.Set("db_instance_ids", scaling.DBInstanceIds) + d.Set("loadbalancer_ids", scaling.LoadBalancerId) + + return nil +} + +func resourceAliyunEssScalingGroupUpdate(d *schema.ResourceData, meta interface{}) error { + + conn := meta.(*AliyunClient).essconn + args := &ess.ModifyScalingGroupArgs{ + ScalingGroupId: d.Id(), + } + + if d.HasChange("scaling_group_name") { + args.ScalingGroupName = d.Get("scaling_group_name").(string) + } + + if d.HasChange("min_size") { + args.MinSize = d.Get("min_size").(int) + } + + if d.HasChange("max_size") { + args.MaxSize = d.Get("max_size").(int) + } + + if d.HasChange("default_cooldown") { + args.DefaultCooldown = d.Get("default_cooldown").(int) + } + + if d.HasChange("removal_policies") { + policyStrings := d.Get("removal_policies").([]interface{}) + args.RemovalPolicy = expandStringList(policyStrings) + } + + if _, err := conn.ModifyScalingGroup(args); err != nil { + return err + } + + return resourceAliyunEssScalingGroupRead(d, meta) +} + +func resourceAliyunEssScalingGroupDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AliyunClient) + + return resource.Retry(2*time.Minute, func() *resource.RetryError { + err := client.DeleteScalingGroupById(d.Id()) + + 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.")) + } + } + + _, err = client.DescribeScalingGroupById(d.Id()) + if err != nil { + if notFoundError(err) { + return nil + } + return resource.NonRetryableError(err) + } + + return resource.RetryableError(fmt.Errorf("Scaling group in use - trying again while it is deleted.")) + }) +} + +func buildAlicloudEssScalingGroupArgs(d *schema.ResourceData, meta interface{}) (*ess.CreateScalingGroupArgs, error) { + client := meta.(*AliyunClient) + args := &ess.CreateScalingGroupArgs{ + RegionId: getRegion(d, meta), + MinSize: d.Get("min_size").(int), + MaxSize: d.Get("max_size").(int), + DefaultCooldown: d.Get("default_cooldown").(int), + } + + if v := d.Get("scaling_group_name").(string); v != "" { + args.ScalingGroupName = v + } + + if v := d.Get("vswitch_id").(string); v != "" { + args.VSwitchId = v + + // get vpcId + vpcId, err := client.GetVpcIdByVSwitchId(v) + + if err != nil { + return nil, fmt.Errorf("VswitchId %s is not valid of current region", v) + } + // fill vpcId by vswitchId + args.VpcId = vpcId + + } + + dbs, ok := d.GetOk("db_instance_ids") + if ok { + dbsStrings := dbs.([]interface{}) + args.DBInstanceId = expandStringList(dbsStrings) + } + + lbs, ok := d.GetOk("loadbalancer_ids") + if ok { + lbsStrings := lbs.([]interface{}) + args.LoadBalancerId = strings.Join(expandStringList(lbsStrings), COMMA_SEPARATED) + } + + return args, nil +} diff --git a/builtin/providers/alicloud/resource_alicloud_ess_scalinggroup_test.go b/builtin/providers/alicloud/resource_alicloud_ess_scalinggroup_test.go new file mode 100644 index 000000000..e707035b1 --- /dev/null +++ b/builtin/providers/alicloud/resource_alicloud_ess_scalinggroup_test.go @@ -0,0 +1,297 @@ +package alicloud + +import ( + "fmt" + "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ess" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "log" + "testing" +) + +func TestAccAlicloudEssScalingGroup_basic(t *testing.T) { + var sg ess.ScalingGroupItemType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_ess_scaling_group.foo", + + Providers: testAccProviders, + CheckDestroy: testAccCheckEssScalingGroupDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccEssScalingGroupConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingGroupExists( + "alicloud_ess_scaling_group.foo", &sg), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "min_size", + "1"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "max_size", + "1"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "scaling_group_name", + "foo"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "removal_policies.#", + "2", + ), + ), + }, + }, + }) + +} + +func TestAccAlicloudEssScalingGroup_update(t *testing.T) { + var sg ess.ScalingGroupItemType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_ess_scaling_group.foo", + + Providers: testAccProviders, + CheckDestroy: testAccCheckEssScalingGroupDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccEssScalingGroup, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingGroupExists( + "alicloud_ess_scaling_group.foo", &sg), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "min_size", + "1"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "max_size", + "1"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "scaling_group_name", + "foo"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "removal_policies.#", + "2", + ), + ), + }, + + resource.TestStep{ + Config: testAccEssScalingGroup_update, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingGroupExists( + "alicloud_ess_scaling_group.foo", &sg), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "min_size", + "2"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "max_size", + "2"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "scaling_group_name", + "update"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "removal_policies.#", + "1", + ), + ), + }, + }, + }) + +} + +func SkipTestAccAlicloudEssScalingGroup_vpc(t *testing.T) { + var sg ess.ScalingGroupItemType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_ess_scaling_group.foo", + + Providers: testAccProviders, + CheckDestroy: testAccCheckEssScalingGroupDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccEssScalingGroup_vpc, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingGroupExists( + "alicloud_ess_scaling_group.foo", &sg), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "min_size", + "1"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "max_size", + "1"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "scaling_group_name", + "foo"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_group.foo", + "removal_policies.#", + "2", + ), + ), + }, + }, + }) + +} + +func testAccCheckEssScalingGroupExists(n string, d *ess.ScalingGroupItemType) 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 ESS Scaling Group ID is set") + } + + client := testAccProvider.Meta().(*AliyunClient) + attr, err := client.DescribeScalingGroupById(rs.Primary.ID) + log.Printf("[DEBUG] check scaling group %s attribute %#v", rs.Primary.ID, attr) + + if err != nil { + return err + } + + if attr == nil { + return fmt.Errorf("Scaling Group not found") + } + + *d = *attr + return nil + } +} + +func testAccCheckEssScalingGroupDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*AliyunClient) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "alicloud_ess_scaling_group" { + continue + } + + ins, err := client.DescribeScalingGroupById(rs.Primary.ID) + + if ins != nil { + return fmt.Errorf("Error ESS scaling group still exist") + } + + // Verify the error is what we want + if err != nil { + // Verify the error is what we want + e, _ := err.(*common.Error) + if e.ErrorResponse.Code == InstanceNotfound { + continue + } + return err + } + } + + return nil +} + +const testAccEssScalingGroupConfig = ` +resource "alicloud_ess_scaling_group" "foo" { + min_size = 1 + max_size = 1 + scaling_group_name = "foo" + removal_policies = ["OldestInstance", "NewestInstance"] +} +` + +const testAccEssScalingGroup = ` +resource "alicloud_ess_scaling_group" "foo" { + min_size = 1 + max_size = 1 + scaling_group_name = "foo" + removal_policies = ["OldestInstance", "NewestInstance"] +} +` + +const testAccEssScalingGroup_update = ` +resource "alicloud_ess_scaling_group" "foo" { + min_size = 2 + max_size = 2 + scaling_group_name = "update" + removal_policies = ["OldestInstance"] +} +` +const testAccEssScalingGroup_vpc = ` +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} + +data "alicloud_zones" "default" { + "available_disk_category"= "cloud_efficiency" + "available_resource_creation"= "VSwitch" +} + +resource "alicloud_vpc" "foo" { + name = "tf_test_foo" + cidr_block = "172.16.0.0/12" +} + +resource "alicloud_vswitch" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "172.16.0.0/21" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" +} + +resource "alicloud_security_group" "tf_test_foo" { + description = "foo" + vpc_id = "${alicloud_vpc.foo.id}" +} + +resource "alicloud_ess_scaling_group" "foo" { + min_size = 1 + max_size = 1 + scaling_group_name = "foo" + default_cooldown = 20 + vswitch_id = "${alicloud_vswitch.foo.id}" + removal_policies = ["OldestInstance", "NewestInstance"] +} + +resource "alicloud_ess_scaling_configuration" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.foo.id}" + enable = true + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.n1.medium" + io_optimized = "optimized" + system_disk_category = "cloud_efficiency" + internet_charge_type = "PayByTraffic" + internet_max_bandwidth_out = 10 + security_group_id = "${alicloud_security_group.tf_test_foo.id}" +} +` diff --git a/builtin/providers/alicloud/resource_alicloud_ess_scalingrule.go b/builtin/providers/alicloud/resource_alicloud_ess_scalingrule.go new file mode 100644 index 000000000..bfa1f904f --- /dev/null +++ b/builtin/providers/alicloud/resource_alicloud_ess_scalingrule.go @@ -0,0 +1,168 @@ +package alicloud + +import ( + "fmt" + "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ess" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "strings" + "time" +) + +func resourceAlicloudEssScalingRule() *schema.Resource { + return &schema.Resource{ + Create: resourceAliyunEssScalingRuleCreate, + Read: resourceAliyunEssScalingRuleRead, + Update: resourceAliyunEssScalingRuleUpdate, + Delete: resourceAliyunEssScalingRuleDelete, + + Schema: map[string]*schema.Schema{ + "scaling_group_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "adjustment_type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validateAllowedStringValue([]string{string(ess.QuantityChangeInCapacity), + string(ess.PercentChangeInCapacity), string(ess.TotalCapacity)}), + }, + "adjustment_value": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + "scaling_rule_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "ari": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "cooldown": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validateIntegerInRange(0, 86400), + }, + }, + } +} + +func resourceAliyunEssScalingRuleCreate(d *schema.ResourceData, meta interface{}) error { + + args, err := buildAlicloudEssScalingRuleArgs(d, meta) + if err != nil { + return err + } + + essconn := meta.(*AliyunClient).essconn + + rule, err := essconn.CreateScalingRule(args) + if err != nil { + return err + } + + d.SetId(d.Get("scaling_group_id").(string) + COLON_SEPARATED + rule.ScalingRuleId) + + return resourceAliyunEssScalingRuleUpdate(d, meta) +} + +func resourceAliyunEssScalingRuleRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*AliyunClient) + ids := strings.Split(d.Id(), COLON_SEPARATED) + + rule, err := client.DescribeScalingRuleById(ids[0], ids[1]) + if err != nil { + if e, ok := err.(*common.Error); ok && e.Code == InstanceNotfound { + d.SetId("") + return nil + } + return fmt.Errorf("Error Describe ESS scaling rule Attribute: %#v", err) + } + + d.Set("scaling_group_id", rule.ScalingGroupId) + d.Set("ari", rule.ScalingRuleAri) + d.Set("adjustment_type", rule.AdjustmentType) + d.Set("adjustment_value", rule.AdjustmentValue) + d.Set("scaling_rule_name", rule.ScalingRuleName) + d.Set("cooldown", rule.Cooldown) + + return nil +} + +func resourceAliyunEssScalingRuleDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AliyunClient) + ids := strings.Split(d.Id(), COLON_SEPARATED) + + return resource.Retry(2*time.Minute, func() *resource.RetryError { + err := client.DeleteScalingRuleById(ids[1]) + + if err != nil { + return resource.RetryableError(fmt.Errorf("Scaling rule in use - trying again while it is deleted.")) + } + + _, err = client.DescribeScalingRuleById(ids[0], ids[1]) + if err != nil { + if notFoundError(err) { + return nil + } + return resource.NonRetryableError(err) + } + + return resource.RetryableError(fmt.Errorf("Scaling rule in use - trying again while it is deleted.")) + }) +} + +func resourceAliyunEssScalingRuleUpdate(d *schema.ResourceData, meta interface{}) error { + + conn := meta.(*AliyunClient).essconn + ids := strings.Split(d.Id(), COLON_SEPARATED) + + args := &ess.ModifyScalingRuleArgs{ + ScalingRuleId: ids[1], + } + + if d.HasChange("adjustment_type") { + args.AdjustmentType = ess.AdjustmentType(d.Get("adjustment_type").(string)) + } + + if d.HasChange("adjustment_value") { + args.AdjustmentValue = d.Get("adjustment_value").(int) + } + + if d.HasChange("scaling_rule_name") { + args.ScalingRuleName = d.Get("scaling_rule_name").(string) + } + + if d.HasChange("cooldown") { + args.Cooldown = d.Get("cooldown").(int) + } + + if _, err := conn.ModifyScalingRule(args); err != nil { + return err + } + + return resourceAliyunEssScalingRuleRead(d, meta) +} + +func buildAlicloudEssScalingRuleArgs(d *schema.ResourceData, meta interface{}) (*ess.CreateScalingRuleArgs, error) { + args := &ess.CreateScalingRuleArgs{ + RegionId: getRegion(d, meta), + ScalingGroupId: d.Get("scaling_group_id").(string), + AdjustmentType: ess.AdjustmentType(d.Get("adjustment_type").(string)), + AdjustmentValue: d.Get("adjustment_value").(int), + } + + if v := d.Get("scaling_rule_name").(string); v != "" { + args.ScalingRuleName = v + } + + if v := d.Get("cooldown").(int); v != 0 { + args.Cooldown = v + } + + return args, nil +} diff --git a/builtin/providers/alicloud/resource_alicloud_ess_scalingrule_test.go b/builtin/providers/alicloud/resource_alicloud_ess_scalingrule_test.go new file mode 100644 index 000000000..81020a747 --- /dev/null +++ b/builtin/providers/alicloud/resource_alicloud_ess_scalingrule_test.go @@ -0,0 +1,290 @@ +package alicloud + +import ( + "fmt" + "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ess" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "log" + "strings" + "testing" +) + +func TestAccAlicloudEssScalingRule_basic(t *testing.T) { + var sc ess.ScalingRuleItemType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_ess_scaling_rule.foo", + + Providers: testAccProviders, + CheckDestroy: testAccCheckEssScalingRuleDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccEssScalingRuleConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingRuleExists( + "alicloud_ess_scaling_rule.foo", &sc), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_rule.foo", + "adjustment_type", + "TotalCapacity"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_rule.foo", + "adjustment_value", + "1"), + ), + }, + }, + }) +} + +func TestAccAlicloudEssScalingRule_update(t *testing.T) { + var sc ess.ScalingRuleItemType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_ess_scaling_rule.foo", + + Providers: testAccProviders, + CheckDestroy: testAccCheckEssScalingRuleDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccEssScalingRule, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingRuleExists( + "alicloud_ess_scaling_rule.foo", &sc), + testAccCheckEssScalingRuleExists( + "alicloud_ess_scaling_rule.foo", &sc), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_rule.foo", + "adjustment_type", + "TotalCapacity"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_rule.foo", + "adjustment_value", + "1"), + ), + }, + + resource.TestStep{ + Config: testAccEssScalingRule_update, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScalingRuleExists( + "alicloud_ess_scaling_rule.foo", &sc), + testAccCheckEssScalingRuleExists( + "alicloud_ess_scaling_rule.foo", &sc), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_rule.foo", + "adjustment_type", + "TotalCapacity"), + resource.TestCheckResourceAttr( + "alicloud_ess_scaling_rule.foo", + "adjustment_value", + "2"), + ), + }, + }, + }) +} + +func testAccCheckEssScalingRuleExists(n string, d *ess.ScalingRuleItemType) 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 ESS Scaling Rule ID is set") + } + + client := testAccProvider.Meta().(*AliyunClient) + ids := strings.Split(rs.Primary.ID, COLON_SEPARATED) + attr, err := client.DescribeScalingRuleById(ids[0], ids[1]) + log.Printf("[DEBUG] check scaling rule %s attribute %#v", rs.Primary.ID, attr) + + if err != nil { + return err + } + + if attr == nil { + return fmt.Errorf("Scaling rule not found") + } + + *d = *attr + return nil + } +} + +func testAccCheckEssScalingRuleDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*AliyunClient) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "alicloud_ess_scaling_rule" { + continue + } + ids := strings.Split(rs.Primary.ID, COLON_SEPARATED) + ins, err := client.DescribeScalingRuleById(ids[0], ids[1]) + + if ins != nil { + return fmt.Errorf("Error ESS scaling rule still exist") + } + + // Verify the error is what we want + if err != nil { + // Verify the error is what we want + e, _ := err.(*common.Error) + if e.ErrorResponse.Code == InstanceNotfound { + continue + } + return err + } + } + + return nil +} + +const testAccEssScalingRuleConfig = ` +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} + +resource "alicloud_security_group" "tf_test_foo" { + description = "foo" +} + +resource "alicloud_security_group_rule" "ssh-in" { + type = "ingress" + ip_protocol = "tcp" + nic_type = "internet" + policy = "accept" + port_range = "22/22" + priority = 1 + security_group_id = "${alicloud_security_group.tf_test_foo.id}" + cidr_ip = "0.0.0.0/0" +} + +resource "alicloud_ess_scaling_group" "bar" { + min_size = 1 + max_size = 1 + scaling_group_name = "bar" + removal_policies = ["OldestInstance", "NewestInstance"] +} + +resource "alicloud_ess_scaling_configuration" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.bar.id}" + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.s2.large" + io_optimized = "optimized" + security_group_id = "${alicloud_security_group.tf_test_foo.id}" +} + +resource "alicloud_ess_scaling_rule" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.bar.id}" + adjustment_type = "TotalCapacity" + adjustment_value = 1 + cooldown = 120 +} +` + +const testAccEssScalingRule = ` +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} + +resource "alicloud_security_group" "tf_test_foo" { + description = "foo" +} + +resource "alicloud_security_group_rule" "ssh-in" { + type = "ingress" + ip_protocol = "tcp" + nic_type = "internet" + policy = "accept" + port_range = "22/22" + priority = 1 + security_group_id = "${alicloud_security_group.tf_test_foo.id}" + cidr_ip = "0.0.0.0/0" +} + +resource "alicloud_ess_scaling_group" "bar" { + min_size = 1 + max_size = 1 + scaling_group_name = "bar" + removal_policies = ["OldestInstance", "NewestInstance"] +} + +resource "alicloud_ess_scaling_configuration" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.bar.id}" + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.s2.large" + io_optimized = "optimized" + security_group_id = "${alicloud_security_group.tf_test_foo.id}" +} + +resource "alicloud_ess_scaling_rule" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.bar.id}" + adjustment_type = "TotalCapacity" + adjustment_value = 1 + cooldown = 120 +} +` + +const testAccEssScalingRule_update = ` +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} + +resource "alicloud_security_group" "tf_test_foo" { + description = "foo" +} + +resource "alicloud_security_group_rule" "ssh-in" { + type = "ingress" + ip_protocol = "tcp" + nic_type = "internet" + policy = "accept" + port_range = "22/22" + priority = 1 + security_group_id = "${alicloud_security_group.tf_test_foo.id}" + cidr_ip = "0.0.0.0/0" +} + +resource "alicloud_ess_scaling_group" "bar" { + min_size = 1 + max_size = 1 + scaling_group_name = "bar" + removal_policies = ["OldestInstance", "NewestInstance"] +} + +resource "alicloud_ess_scaling_configuration" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.bar.id}" + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.s2.large" + io_optimized = "optimized" + security_group_id = "${alicloud_security_group.tf_test_foo.id}" +} + +resource "alicloud_ess_scaling_rule" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.bar.id}" + adjustment_type = "TotalCapacity" + adjustment_value = 2 + cooldown = 60 +} +` diff --git a/builtin/providers/alicloud/resource_alicloud_ess_schedule.go b/builtin/providers/alicloud/resource_alicloud_ess_schedule.go new file mode 100644 index 000000000..4e5660a50 --- /dev/null +++ b/builtin/providers/alicloud/resource_alicloud_ess_schedule.go @@ -0,0 +1,220 @@ +package alicloud + +import ( + "fmt" + "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ess" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "time" +) + +func resourceAlicloudEssSchedule() *schema.Resource { + return &schema.Resource{ + Create: resourceAliyunEssScheduleCreate, + Read: resourceAliyunEssScheduleRead, + Update: resourceAliyunEssScheduleUpdate, + Delete: resourceAliyunEssScheduleDelete, + + Schema: map[string]*schema.Schema{ + "scheduled_action": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "launch_time": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "scheduled_task_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "launch_expiration_time": &schema.Schema{ + Type: schema.TypeInt, + Default: 600, + Optional: true, + ValidateFunc: validateIntegerInRange(0, 21600), + }, + "recurrence_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + ValidateFunc: validateAllowedStringValue([]string{string(ess.Daily), + string(ess.Weekly), string(ess.Monthly)}), + }, + "recurrence_value": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "recurrence_end_time": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + "task_enabled": &schema.Schema{ + Type: schema.TypeBool, + Default: true, + Optional: true, + }, + }, + } +} + +func resourceAliyunEssScheduleCreate(d *schema.ResourceData, meta interface{}) error { + + args, err := buildAlicloudEssScheduleArgs(d, meta) + if err != nil { + return err + } + + essconn := meta.(*AliyunClient).essconn + + rule, err := essconn.CreateScheduledTask(args) + if err != nil { + return err + } + + d.SetId(rule.ScheduledTaskId) + + return resourceAliyunEssScheduleUpdate(d, meta) +} + +func resourceAliyunEssScheduleRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*AliyunClient) + + rule, err := client.DescribeScheduleById(d.Id()) + if err != nil { + if e, ok := err.(*common.Error); ok && e.Code == InstanceNotfound { + d.SetId("") + return nil + } + return fmt.Errorf("Error Describe ESS schedule Attribute: %#v", err) + } + + d.Set("scheduled_action", rule.ScheduledAction) + d.Set("launch_time", rule.LaunchTime) + d.Set("scheduled_task_name", rule.ScheduledTaskName) + d.Set("description", rule.Description) + d.Set("launch_expiration_time", rule.LaunchExpirationTime) + d.Set("recurrence_type", rule.RecurrenceType) + d.Set("recurrence_value", rule.RecurrenceValue) + d.Set("recurrence_end_time", rule.RecurrenceEndTime) + d.Set("task_enabled", rule.TaskEnabled) + + return nil +} + +func resourceAliyunEssScheduleUpdate(d *schema.ResourceData, meta interface{}) error { + + conn := meta.(*AliyunClient).essconn + + args := &ess.ModifyScheduledTaskArgs{ + ScheduledTaskId: d.Id(), + } + + if d.HasChange("scheduled_task_name") { + args.ScheduledTaskName = d.Get("scheduled_task_name").(string) + } + + if d.HasChange("description") { + args.Description = d.Get("description").(string) + } + + if d.HasChange("scheduled_action") { + args.ScheduledAction = d.Get("scheduled_action").(string) + } + + if d.HasChange("launch_time") { + args.LaunchTime = d.Get("launch_time").(string) + } + + if d.HasChange("launch_expiration_time") { + args.LaunchExpirationTime = d.Get("launch_expiration_time").(int) + } + + if d.HasChange("recurrence_type") { + args.RecurrenceType = ess.RecurrenceType(d.Get("recurrence_type").(string)) + } + + if d.HasChange("recurrence_value") { + args.RecurrenceValue = d.Get("recurrence_value").(string) + } + + if d.HasChange("recurrence_end_time") { + args.RecurrenceEndTime = d.Get("recurrence_end_time").(string) + } + + if d.HasChange("task_enabled") { + args.TaskEnabled = d.Get("task_enabled").(bool) + } + + if _, err := conn.ModifyScheduledTask(args); err != nil { + return err + } + + return resourceAliyunEssScheduleRead(d, meta) +} + +func resourceAliyunEssScheduleDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AliyunClient) + + return resource.Retry(2*time.Minute, func() *resource.RetryError { + err := client.DeleteScheduleById(d.Id()) + + if err != nil { + return resource.RetryableError(fmt.Errorf("Scaling schedule in use - trying again while it is deleted.")) + } + + _, err = client.DescribeScheduleById(d.Id()) + if err != nil { + if notFoundError(err) { + return nil + } + return resource.NonRetryableError(err) + } + + return resource.RetryableError(fmt.Errorf("Scaling schedule in use - trying again while it is deleted.")) + }) +} + +func buildAlicloudEssScheduleArgs(d *schema.ResourceData, meta interface{}) (*ess.CreateScheduledTaskArgs, error) { + args := &ess.CreateScheduledTaskArgs{ + RegionId: getRegion(d, meta), + ScheduledAction: d.Get("scheduled_action").(string), + LaunchTime: d.Get("launch_time").(string), + TaskEnabled: d.Get("task_enabled").(bool), + } + + if v := d.Get("scheduled_task_name").(string); v != "" { + args.ScheduledTaskName = v + } + + if v := d.Get("description").(string); v != "" { + args.Description = v + } + + if v := d.Get("recurrence_type").(string); v != "" { + args.RecurrenceType = ess.RecurrenceType(v) + } + + if v := d.Get("recurrence_value").(string); v != "" { + args.RecurrenceValue = v + } + + if v := d.Get("recurrence_end_time").(string); v != "" { + args.RecurrenceEndTime = v + } + + if v := d.Get("launch_expiration_time").(int); v != 0 { + args.LaunchExpirationTime = v + } + + return args, nil +} diff --git a/builtin/providers/alicloud/resource_alicloud_ess_schedule_test.go b/builtin/providers/alicloud/resource_alicloud_ess_schedule_test.go new file mode 100644 index 000000000..cb8044cc4 --- /dev/null +++ b/builtin/providers/alicloud/resource_alicloud_ess_schedule_test.go @@ -0,0 +1,151 @@ +package alicloud + +import ( + "fmt" + "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ess" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "log" + "testing" +) + +func TestAccAlicloudEssSchedule_basic(t *testing.T) { + var sc ess.ScheduledTaskItemType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_ess_schedule.foo", + + Providers: testAccProviders, + CheckDestroy: testAccCheckEssScheduleDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccEssScheduleConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckEssScheduleExists( + "alicloud_ess_schedule.foo", &sc), + resource.TestCheckResourceAttr( + "alicloud_ess_schedule.foo", + "launch_time", + "2017-04-29T07:30Z"), + resource.TestCheckResourceAttr( + "alicloud_ess_schedule.foo", + "task_enabled", + "true"), + ), + }, + }, + }) +} + +func testAccCheckEssScheduleExists(n string, d *ess.ScheduledTaskItemType) 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 ESS Schedule ID is set") + } + + client := testAccProvider.Meta().(*AliyunClient) + attr, err := client.DescribeScheduleById(rs.Primary.ID) + log.Printf("[DEBUG] check schedule %s attribute %#v", rs.Primary.ID, attr) + + if err != nil { + return err + } + + if attr == nil { + return fmt.Errorf("Ess schedule not found") + } + + *d = *attr + return nil + } +} + +func testAccCheckEssScheduleDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*AliyunClient) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "alicloud_ess_schedule" { + continue + } + ins, err := client.DescribeScheduleById(rs.Primary.ID) + + if ins != nil { + return fmt.Errorf("Error ESS schedule still exist") + } + + // Verify the error is what we want + if err != nil { + // Verify the error is what we want + e, _ := err.(*common.Error) + if e.ErrorResponse.Code == InstanceNotfound { + continue + } + return err + } + } + + return nil +} + +const testAccEssScheduleConfig = ` +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} + +resource "alicloud_security_group" "tf_test_foo" { + name = "tf_test_foo" + description = "foo" +} + +resource "alicloud_security_group_rule" "ssh-in" { + type = "ingress" + ip_protocol = "tcp" + nic_type = "internet" + policy = "accept" + port_range = "22/22" + priority = 1 + security_group_id = "${alicloud_security_group.tf_test_foo.id}" + cidr_ip = "0.0.0.0/0" +} + +resource "alicloud_ess_scaling_group" "bar" { + min_size = 1 + max_size = 1 + scaling_group_name = "bar" + removal_policies = ["OldestInstance", "NewestInstance"] +} + +resource "alicloud_ess_scaling_configuration" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.bar.id}" + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "ecs.s2.large" + io_optimized = "optimized" + security_group_id = "${alicloud_security_group.tf_test_foo.id}" +} + +resource "alicloud_ess_scaling_rule" "foo" { + scaling_group_id = "${alicloud_ess_scaling_group.bar.id}" + adjustment_type = "TotalCapacity" + adjustment_value = 2 + cooldown = 60 +} + +resource "alicloud_ess_schedule" "foo" { + scheduled_action = "${alicloud_ess_scaling_rule.foo.ari}" + launch_time = "2017-04-29T07:30Z" + scheduled_task_name = "tf-foo" +} +` diff --git a/builtin/providers/alicloud/resource_alicloud_forward.go b/builtin/providers/alicloud/resource_alicloud_forward.go new file mode 100644 index 000000000..8f75c54d0 --- /dev/null +++ b/builtin/providers/alicloud/resource_alicloud_forward.go @@ -0,0 +1,165 @@ +package alicloud + +import ( + "fmt" + "github.com/denverdino/aliyungo/ecs" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAliyunForwardEntry() *schema.Resource { + return &schema.Resource{ + Create: resourceAliyunForwardEntryCreate, + Read: resourceAliyunForwardEntryRead, + Update: resourceAliyunForwardEntryUpdate, + Delete: resourceAliyunForwardEntryDelete, + + Schema: map[string]*schema.Schema{ + "forward_table_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "external_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "external_port": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validateForwardPort, + }, + "ip_protocol": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validateAllowedStringValue([]string{"tcp", "udp", "any"}), + }, + "internal_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "internal_port": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ValidateFunc: validateForwardPort, + }, + }, + } +} + +func resourceAliyunForwardEntryCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AliyunClient).vpcconn + + args := &ecs.CreateForwardEntryArgs{ + RegionId: getRegion(d, meta), + ForwardTableId: d.Get("forward_table_id").(string), + ExternalIp: d.Get("external_ip").(string), + ExternalPort: d.Get("external_port").(string), + IpProtocol: d.Get("ip_protocol").(string), + InternalIp: d.Get("internal_ip").(string), + InternalPort: d.Get("internal_port").(string), + } + + resp, err := conn.CreateForwardEntry(args) + if err != nil { + return fmt.Errorf("CreateForwardEntry got error: %#v", err) + } + + d.SetId(resp.ForwardEntryId) + d.Set("forward_table_id", d.Get("forward_table_id").(string)) + + return resourceAliyunForwardEntryRead(d, meta) +} + +func resourceAliyunForwardEntryRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AliyunClient) + + forwardEntry, err := client.DescribeForwardEntry(d.Get("forward_table_id").(string), d.Id()) + + if err != nil { + if notFoundError(err) { + return nil + } + return err + } + + d.Set("forward_table_id", forwardEntry.ForwardTableId) + d.Set("external_ip", forwardEntry.ExternalIp) + d.Set("external_port", forwardEntry.ExternalPort) + d.Set("ip_protocol", forwardEntry.IpProtocol) + d.Set("internal_ip", forwardEntry.InternalIp) + d.Set("internal_port", forwardEntry.InternalPort) + + return nil +} + +func resourceAliyunForwardEntryUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AliyunClient) + conn := client.vpcconn + + forwardEntry, err := client.DescribeForwardEntry(d.Get("forward_table_id").(string), d.Id()) + if err != nil { + return err + } + + d.Partial(true) + attributeUpdate := false + args := &ecs.ModifyForwardEntryArgs{ + RegionId: getRegion(d, meta), + ForwardTableId: forwardEntry.ForwardTableId, + ForwardEntryId: forwardEntry.ForwardEntryId, + ExternalIp: forwardEntry.ExternalIp, + IpProtocol: forwardEntry.IpProtocol, + ExternalPort: forwardEntry.ExternalPort, + InternalIp: forwardEntry.InternalIp, + InternalPort: forwardEntry.InternalPort, + } + + if d.HasChange("external_port") { + d.SetPartial("external_port") + args.ExternalPort = d.Get("external_port").(string) + attributeUpdate = true + } + + if d.HasChange("ip_protocol") { + d.SetPartial("ip_protocol") + args.IpProtocol = d.Get("ip_protocol").(string) + attributeUpdate = true + } + + if d.HasChange("internal_port") { + d.SetPartial("internal_port") + args.InternalPort = d.Get("internal_port").(string) + attributeUpdate = true + } + + if attributeUpdate { + if err := conn.ModifyForwardEntry(args); err != nil { + return err + } + } + + d.Partial(false) + + return resourceAliyunForwardEntryRead(d, meta) +} + +func resourceAliyunForwardEntryDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AliyunClient) + conn := client.vpcconn + + forwardEntryId := d.Id() + forwardTableId := d.Get("forward_table_id").(string) + + args := &ecs.DeleteForwardEntryArgs{ + RegionId: getRegion(d, meta), + ForwardTableId: forwardTableId, + ForwardEntryId: forwardEntryId, + } + + if err := conn.DeleteForwardEntry(args); err != nil { + return err + } + + return nil +} diff --git a/builtin/providers/alicloud/resource_alicloud_forward_test.go b/builtin/providers/alicloud/resource_alicloud_forward_test.go new file mode 100644 index 000000000..60a67f322 --- /dev/null +++ b/builtin/providers/alicloud/resource_alicloud_forward_test.go @@ -0,0 +1,216 @@ +package alicloud + +import ( + "fmt" + "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ecs" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "testing" +) + +func TestAccAlicloudForward_basic(t *testing.T) { + var forward ecs.ForwardTableEntrySetType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_forward_entry.foo", + Providers: testAccProviders, + CheckDestroy: testAccCheckForwardEntryDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccForwardEntryConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckForwardEntryExists( + "alicloud_forward_entry.foo", &forward), + ), + }, + + resource.TestStep{ + Config: testAccForwardEntryUpdate, + Check: resource.ComposeTestCheckFunc( + testAccCheckForwardEntryExists( + "alicloud_forward_entry.foo", &forward), + ), + }, + }, + }) + +} + +func testAccCheckForwardEntryDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*AliyunClient) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "alicloud_snat_entry" { + continue + } + + // Try to find the Snat entry + instance, err := client.DescribeForwardEntry(rs.Primary.Attributes["forward_table_id"], rs.Primary.ID) + + //this special deal cause the DescribeSnatEntry can't find the records would be throw "cant find the snatTable error" + if instance.ForwardEntryId == "" { + return nil + } + + if instance.ForwardEntryId != "" { + return fmt.Errorf("Forward entry still exist") + } + + if err != nil { + // Verify the error is what we want + e, _ := err.(*common.Error) + + if !notFoundError(e) { + return err + } + } + + } + + return nil +} + +func testAccCheckForwardEntryExists(n string, snat *ecs.ForwardTableEntrySetType) 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 ForwardEntry ID is set") + } + + client := testAccProvider.Meta().(*AliyunClient) + instance, err := client.DescribeForwardEntry(rs.Primary.Attributes["forward_table_id"], rs.Primary.ID) + + if err != nil { + return err + } + if instance.ForwardEntryId == "" { + return fmt.Errorf("ForwardEntry not found") + } + + *snat = instance + return nil + } +} + +const testAccForwardEntryConfig = ` +provider "alicloud"{ + region = "cn-hangzhou" +} + +data "alicloud_zones" "default" { + "available_resource_creation"= "VSwitch" +} + +resource "alicloud_vpc" "foo" { + name = "tf_test_foo" + cidr_block = "172.16.0.0/12" +} + +resource "alicloud_vswitch" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "172.16.0.0/21" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" +} + +resource "alicloud_nat_gateway" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + spec = "Small" + name = "test_foo" + bandwidth_packages = [{ + ip_count = 1 + bandwidth = 5 + zone = "${data.alicloud_zones.default.zones.0.id}" + },{ + ip_count = 1 + bandwidth = 6 + zone = "${data.alicloud_zones.default.zones.0.id}" + }] + depends_on = [ + "alicloud_vswitch.foo"] +} + +resource "alicloud_forward_entry" "foo"{ + forward_table_id = "${alicloud_nat_gateway.foo.forward_table_ids}" + external_ip = "${alicloud_nat_gateway.foo.bandwidth_packages.0.public_ip_addresses}" + external_port = "80" + ip_protocol = "tcp" + internal_ip = "172.16.0.3" + internal_port = "8080" +} + +resource "alicloud_forward_entry" "foo1"{ + forward_table_id = "${alicloud_nat_gateway.foo.forward_table_ids}" + external_ip = "${alicloud_nat_gateway.foo.bandwidth_packages.0.public_ip_addresses}" + external_port = "443" + ip_protocol = "udp" + internal_ip = "172.16.0.4" + internal_port = "8080" +} +` + +const testAccForwardEntryUpdate = ` +provider "alicloud"{ + region = "cn-hangzhou" +} + +data "alicloud_zones" "default" { + "available_resource_creation"= "VSwitch" +} + +resource "alicloud_vpc" "foo" { + name = "tf_test_foo" + cidr_block = "172.16.0.0/12" +} + +resource "alicloud_vswitch" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "172.16.0.0/21" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" +} + +resource "alicloud_nat_gateway" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + spec = "Small" + name = "test_foo" + bandwidth_packages = [{ + ip_count = 1 + bandwidth = 5 + zone = "${data.alicloud_zones.default.zones.0.id}" + },{ + ip_count = 1 + bandwidth = 6 + zone = "${data.alicloud_zones.default.zones.0.id}" + }] + depends_on = [ + "alicloud_vswitch.foo"] +} + +resource "alicloud_forward_entry" "foo"{ + forward_table_id = "${alicloud_nat_gateway.foo.forward_table_ids}" + external_ip = "${alicloud_nat_gateway.foo.bandwidth_packages.0.public_ip_addresses}" + external_port = "80" + ip_protocol = "tcp" + internal_ip = "172.16.0.3" + internal_port = "8081" +} + + +resource "alicloud_forward_entry" "foo1"{ + forward_table_id = "${alicloud_nat_gateway.foo.forward_table_ids}" + external_ip = "${alicloud_nat_gateway.foo.bandwidth_packages.0.public_ip_addresses}" + external_port = "22" + ip_protocol = "udp" + internal_ip = "172.16.0.4" + internal_port = "8080" +} +` diff --git a/builtin/providers/alicloud/resource_alicloud_instance.go b/builtin/providers/alicloud/resource_alicloud_instance.go index 36297afbe..492780917 100644 --- a/builtin/providers/alicloud/resource_alicloud_instance.go +++ b/builtin/providers/alicloud/resource_alicloud_instance.go @@ -6,11 +6,12 @@ import ( "encoding/base64" "encoding/json" - "strings" - "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/ecs" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" + "strings" + "time" ) func resourceAliyunInstance() *schema.Resource { @@ -194,19 +195,16 @@ func resourceAliyunInstanceCreate(d *schema.ResourceData, meta interface{}) erro //d.Set("system_disk_category", d.Get("system_disk_category")) //d.Set("system_disk_size", d.Get("system_disk_size")) + if err := allocateIpAndBandWidthRelative(d, meta); err != nil { + return fmt.Errorf("allocateIpAndBandWidthRelative err: %#v", err) + } + // after instance created, its status is pending, // so we need to wait it become to stopped and then start it if err := conn.WaitForInstance(d.Id(), ecs.Stopped, defaultTimeout); err != nil { log.Printf("[DEBUG] WaitForInstance %s got error: %#v", ecs.Stopped, err) } - if d.Get("allocate_public_ip").(bool) { - _, err := conn.AllocatePublicIpAddress(d.Id()) - if err != nil { - log.Printf("[DEBUG] AllocatePublicIpAddress for instance got error: %#v", err) - } - } - if err := conn.StartInstance(d.Id()); err != nil { return fmt.Errorf("Start instance got error: %#v", err) } @@ -258,11 +256,12 @@ func resourceAliyunRunInstance(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] WaitForInstance %s got error: %#v", ecs.Running, err) } - if d.Get("allocate_public_ip").(bool) { - _, err := conn.AllocatePublicIpAddress(d.Id()) - if err != nil { - log.Printf("[DEBUG] AllocatePublicIpAddress for instance got error: %#v", err) - } + if err := allocateIpAndBandWidthRelative(d, meta); err != nil { + return fmt.Errorf("allocateIpAndBandWidthRelative err: %#v", err) + } + + if err := conn.WaitForInstanceAsyn(d.Id(), ecs.Running, defaultTimeout); err != nil { + log.Printf("[DEBUG] WaitForInstance %s got error: %#v", ecs.Running, err) } return resourceAliyunInstanceUpdate(d, meta) @@ -458,30 +457,47 @@ func resourceAliyunInstanceDelete(d *schema.ResourceData, meta interface{}) erro client := meta.(*AliyunClient) conn := client.ecsconn - instance, err := client.QueryInstancesById(d.Id()) - if err != nil { - if notFoundError(err) { - return nil - } - return fmt.Errorf("Error DescribeInstanceAttribute: %#v", err) - } - - if instance.Status != ecs.Stopped { - if err := conn.StopInstance(d.Id(), true); err != nil { - return err + return resource.Retry(5*time.Minute, func() *resource.RetryError { + instance, err := client.QueryInstancesById(d.Id()) + if err != nil { + if notFoundError(err) { + return nil + } } - if err := conn.WaitForInstance(d.Id(), ecs.Stopped, defaultTimeout); err != nil { - return err + if instance.Status != ecs.Stopped { + if err := conn.StopInstance(d.Id(), true); err != nil { + return resource.RetryableError(fmt.Errorf("ECS stop error - trying again.")) + } + + if err := conn.WaitForInstance(d.Id(), ecs.Stopped, defaultTimeout); err != nil { + return resource.RetryableError(fmt.Errorf("Waiting for ecs stopped timeout - trying again.")) + } + } + + if err := conn.DeleteInstance(d.Id()); err != nil { + return resource.RetryableError(fmt.Errorf("ECS Instance in use - trying again while it is deleted.")) + } + + return nil + }) + +} + +func allocateIpAndBandWidthRelative(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AliyunClient).ecsconn + if d.Get("allocate_public_ip").(bool) { + if d.Get("internet_max_bandwidth_out") == 0 { + return fmt.Errorf("Error: if allocate_public_ip is true than the internet_max_bandwidth_out cannot equal zero.") + } + _, err := conn.AllocatePublicIpAddress(d.Id()) + if err != nil { + return fmt.Errorf("[DEBUG] AllocatePublicIpAddress for instance got error: %#v", err) } } - - if err := conn.DeleteInstance(d.Id()); err != nil { - return err - } - return nil } + func buildAliyunRunInstancesArgs(d *schema.ResourceData, meta interface{}) (*ecs.RunInstanceArgs, error) { args := &ecs.RunInstanceArgs{ MaxAmount: DEFAULT_INSTANCE_COUNT, @@ -567,7 +583,6 @@ func buildAliyunInstanceArgs(d *schema.ResourceData, meta interface{}) (*ecs.Cre args.Description = v } - log.Printf("[DEBUG] SystemDisk is %d", systemDiskSize) if v := d.Get("internet_charge_type").(string); v != "" { args.InternetChargeType = common.InternetChargeType(v) } diff --git a/builtin/providers/alicloud/resource_alicloud_nat_gateway.go b/builtin/providers/alicloud/resource_alicloud_nat_gateway.go index 99e71347a..7851e661c 100644 --- a/builtin/providers/alicloud/resource_alicloud_nat_gateway.go +++ b/builtin/providers/alicloud/resource_alicloud_nat_gateway.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "log" + "strconv" "strings" "time" ) @@ -44,6 +45,16 @@ func resourceAliyunNatGateway() *schema.Resource { Computed: true, }, + "snat_table_ids": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + + "forward_table_ids": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "bandwidth_packages": &schema.Schema{ Type: schema.TypeList, Elem: &schema.Resource{ @@ -60,6 +71,10 @@ func resourceAliyunNatGateway() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "public_ip_addresses": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, }, }, Required: true, @@ -133,8 +148,16 @@ func resourceAliyunNatGatewayRead(d *schema.ResourceData, meta interface{}) erro d.Set("name", natGateway.Name) d.Set("spec", natGateway.Spec) d.Set("bandwidth_package_ids", strings.Join(natGateway.BandwidthPackageIds.BandwidthPackageId, ",")) + d.Set("snat_table_ids", strings.Join(natGateway.SnatTableIds.SnatTableId, ",")) + d.Set("forward_table_ids", strings.Join(natGateway.ForwardTableIds.ForwardTableId, ",")) d.Set("description", natGateway.Description) d.Set("vpc_id", natGateway.VpcId) + bindWidthPackages, err := flattenBandWidthPackages(natGateway.BandwidthPackageIds.BandwidthPackageId, meta, d) + if err != nil { + log.Printf("[ERROR] bindWidthPackages flattenBandWidthPackages failed. natgateway id is %#v", d.Id()) + } else { + d.Set("bandwidth_packages", bindWidthPackages) + } return nil } @@ -254,7 +277,7 @@ func resourceAliyunNatGatewayDelete(d *schema.ResourceData, meta interface{}) er } args := &ecs.DeleteNatGatewayArgs{ - RegionId: client.Region, + RegionId: getRegion(d, meta), NatGatewayId: d.Id(), } @@ -267,7 +290,7 @@ func resourceAliyunNatGatewayDelete(d *schema.ResourceData, meta interface{}) er } describeArgs := &ecs.DescribeNatGatewaysArgs{ - RegionId: client.Region, + RegionId: getRegion(d, meta), NatGatewayId: d.Id(), } gw, _, gwErr := conn.DescribeNatGateways(describeArgs) @@ -282,3 +305,69 @@ func resourceAliyunNatGatewayDelete(d *schema.ResourceData, meta interface{}) er return resource.RetryableError(fmt.Errorf("NatGateway in use - trying again while it is deleted.")) }) } + +func flattenBandWidthPackages(bandWidthPackageIds []string, meta interface{}, d *schema.ResourceData) ([]map[string]interface{}, error) { + + packageLen := len(bandWidthPackageIds) + result := make([]map[string]interface{}, 0, packageLen) + + for i := packageLen - 1; i >= 0; i-- { + packageId := bandWidthPackageIds[i] + packages, err := getPackages(packageId, meta, d) + if err != nil { + log.Printf("[ERROR] NatGateways getPackages failed. packageId is %#v", packageId) + return result, err + } + ipAddress := flattenPackPublicIp(packages.PublicIpAddresses.PublicIpAddresse) + ipCont, ipContErr := strconv.Atoi(packages.IpCount) + bandWidth, bandWidthErr := strconv.Atoi(packages.Bandwidth) + if ipContErr != nil { + log.Printf("[ERROR] NatGateways getPackages failed: ipCont convert error. packageId is %#v", packageId) + return result, ipContErr + } + if bandWidthErr != nil { + log.Printf("[ERROR] NatGateways getPackages failed: bandWidthErr convert error. packageId is %#v", packageId) + return result, bandWidthErr + } + l := map[string]interface{}{ + "ip_count": ipCont, + "bandwidth": bandWidth, + "zone": packages.ZoneId, + "public_ip_addresses": ipAddress, + } + result = append(result, l) + } + return result, nil +} + +func getPackages(packageId string, meta interface{}, d *schema.ResourceData) (*ecs.DescribeBandwidthPackageType, error) { + client := meta.(*AliyunClient) + conn := client.vpcconn + packages, err := conn.DescribeBandwidthPackages(&ecs.DescribeBandwidthPackagesArgs{ + RegionId: getRegion(d, meta), + BandwidthPackageId: packageId, + }) + + if err != nil { + log.Printf("[ERROR] Describe bandwidth package is failed, BandwidthPackageId Id: %s", packageId) + return nil, err + } + + if len(packages) == 0 { + return nil, common.GetClientErrorFromString(InstanceNotfound) + } + + return &packages[0], nil + +} + +func flattenPackPublicIp(publicIpAddressList []ecs.PublicIpAddresseType) string { + var result []string + + for _, publicIpAddresses := range publicIpAddressList { + ipAddress := publicIpAddresses.IpAddress + result = append(result, ipAddress) + } + + return strings.Join(result, ",") +} diff --git a/builtin/providers/alicloud/resource_alicloud_nat_gateway_test.go b/builtin/providers/alicloud/resource_alicloud_nat_gateway_test.go index a928c5dc1..963be3cb1 100644 --- a/builtin/providers/alicloud/resource_alicloud_nat_gateway_test.go +++ b/builtin/providers/alicloud/resource_alicloud_nat_gateway_test.go @@ -48,6 +48,7 @@ func TestAccAlicloudNatGateway_basic(t *testing.T) { "alicloud_nat_gateway.foo", "name", "test_foo"), + testAccCheckNatgatewayIpAddress("alicloud_nat_gateway.foo", &nat), ), }, }, @@ -96,6 +97,31 @@ func TestAccAlicloudNatGateway_spec(t *testing.T) { } +func testAccCheckNatgatewayIpAddress(n string, nat *ecs.NatGatewaySetType) 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 NatGateway ID is set") + } + + client := testAccProvider.Meta().(*AliyunClient) + natGateway, err := client.DescribeNatGateway(rs.Primary.ID) + + if err != nil { + return err + } + if natGateway == nil { + return fmt.Errorf("Natgateway not found") + } + + return nil + } +} + func testAccCheckNatGatewayExists(n string, nat *ecs.NatGatewaySetType) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -164,7 +190,7 @@ resource "alicloud_vpc" "foo" { resource "alicloud_vswitch" "foo" { vpc_id = "${alicloud_vpc.foo.id}" cidr_block = "172.16.0.0/21" - availability_zone = "${data.alicloud_zones.default.zones.0.id}" + availability_zone = "${data.alicloud_zones.default.zones.2.id}" } resource "alicloud_nat_gateway" "foo" { @@ -174,11 +200,19 @@ resource "alicloud_nat_gateway" "foo" { bandwidth_packages = [{ ip_count = 1 bandwidth = 5 - zone = "${data.alicloud_zones.default.zones.0.id}" + zone = "${data.alicloud_zones.default.zones.2.id}" }, { ip_count = 2 - bandwidth = 10 - zone = "${data.alicloud_zones.default.zones.0.id}" + bandwidth = 6 + zone = "${data.alicloud_zones.default.zones.2.id}" + }, { + ip_count = 3 + bandwidth = 7 + zone = "${data.alicloud_zones.default.zones.2.id}" + }, { + ip_count = 1 + bandwidth = 8 + zone = "${data.alicloud_zones.default.zones.2.id}" }] depends_on = [ "alicloud_vswitch.foo"] diff --git a/builtin/providers/alicloud/resource_alicloud_security_group.go b/builtin/providers/alicloud/resource_alicloud_security_group.go index 5f85bfd29..b1d60f704 100644 --- a/builtin/providers/alicloud/resource_alicloud_security_group.go +++ b/builtin/providers/alicloud/resource_alicloud_security_group.go @@ -74,6 +74,11 @@ func resourceAliyunSecurityGroupRead(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Error DescribeSecurityGroupAttribute: %#v", err) } + if sg == nil { + d.SetId("") + return nil + } + d.Set("name", sg.SecurityGroupName) d.Set("description", sg.Description) diff --git a/builtin/providers/alicloud/resource_alicloud_security_group_rule.go b/builtin/providers/alicloud/resource_alicloud_security_group_rule.go index c43db23a8..56e4de670 100644 --- a/builtin/providers/alicloud/resource_alicloud_security_group_rule.go +++ b/builtin/providers/alicloud/resource_alicloud_security_group_rule.go @@ -3,9 +3,10 @@ package alicloud import ( "fmt" "github.com/denverdino/aliyungo/ecs" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" - "log" "strings" + "time" ) func resourceAliyunSecurityGroupRule() *schema.Resource { @@ -141,7 +142,7 @@ func resourceAliyunSecurityGroupRuleRead(d *schema.ResourceData, meta interface{ } return fmt.Errorf("Error SecurityGroup rule: %#v", err) } - log.Printf("[WARN]sg %s, type %s, protocol %s, port %s, rule %#v", sgId, direction, ip_protocol, port_range, rule) + d.Set("type", rule.Direction) d.Set("ip_protocol", strings.ToLower(string(rule.IpProtocol))) d.Set("nic_type", rule.NicType) @@ -163,7 +164,7 @@ func resourceAliyunSecurityGroupRuleRead(d *schema.ResourceData, meta interface{ return nil } -func resourceAliyunSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{}) error { +func deleteSecurityGroupRule(d *schema.ResourceData, meta interface{}) error { client := meta.(*AliyunClient) ruleType := d.Get("type").(string) @@ -187,6 +188,30 @@ func resourceAliyunSecurityGroupRuleDelete(d *schema.ResourceData, meta interfac AuthorizeSecurityGroupEgressArgs: *args, } return client.RevokeSecurityGroupEgress(revokeArgs) +} + +func resourceAliyunSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AliyunClient) + parts := strings.Split(d.Id(), ":") + sgId, direction, ip_protocol, port_range, nic_type := parts[0], parts[1], parts[2], parts[3], parts[4] + + return resource.Retry(5*time.Minute, func() *resource.RetryError { + err := deleteSecurityGroupRule(d, meta) + + if err != nil { + resource.RetryableError(fmt.Errorf("Security group rule in use - trying again while it is deleted.")) + } + + _, err = client.DescribeSecurityGroupRule(sgId, direction, nic_type, ip_protocol, port_range) + if err != nil { + if notFoundError(err) { + return nil + } + return resource.NonRetryableError(err) + } + + return resource.RetryableError(fmt.Errorf("Security group rule in use - trying again while it is deleted.")) + }) } diff --git a/builtin/providers/alicloud/resource_alicloud_slb.go b/builtin/providers/alicloud/resource_alicloud_slb.go index f3d2af9d3..de8a8906d 100644 --- a/builtin/providers/alicloud/resource_alicloud_slb.go +++ b/builtin/providers/alicloud/resource_alicloud_slb.go @@ -281,6 +281,11 @@ func resourceAliyunSlbRead(d *schema.ResourceData, meta interface{}) error { return err } + if loadBalancer == nil { + d.SetId("") + return nil + } + d.Set("name", loadBalancer.LoadBalancerName) if loadBalancer.AddressType == slb.InternetAddressType { diff --git a/builtin/providers/alicloud/resource_alicloud_slb_attachment.go b/builtin/providers/alicloud/resource_alicloud_slb_attachment.go index 6a9163c07..74e13c26c 100644 --- a/builtin/providers/alicloud/resource_alicloud_slb_attachment.go +++ b/builtin/providers/alicloud/resource_alicloud_slb_attachment.go @@ -64,10 +64,14 @@ func resourceAliyunSlbAttachmentRead(d *schema.ResourceData, meta interface{}) e if err != nil { if notFoundError(err) { d.SetId("") - return fmt.Errorf("Read special SLB Id not found: %#v", err) + return nil } + return fmt.Errorf("Read special SLB Id not found: %#v", err) + } - return err + if loadBalancer == nil { + d.SetId("") + return nil } backendServerType := loadBalancer.BackendServers diff --git a/builtin/providers/alicloud/resource_alicloud_snat.go b/builtin/providers/alicloud/resource_alicloud_snat.go new file mode 100644 index 000000000..887d50388 --- /dev/null +++ b/builtin/providers/alicloud/resource_alicloud_snat.go @@ -0,0 +1,134 @@ +package alicloud + +import ( + "fmt" + "github.com/denverdino/aliyungo/ecs" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAliyunSnatEntry() *schema.Resource { + return &schema.Resource{ + Create: resourceAliyunSnatEntryCreate, + Read: resourceAliyunSnatEntryRead, + Update: resourceAliyunSnatEntryUpdate, + Delete: resourceAliyunSnatEntryDelete, + + Schema: map[string]*schema.Schema{ + "snat_table_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "source_vswitch_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "snat_ip": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +func resourceAliyunSnatEntryCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AliyunClient).vpcconn + + args := &ecs.CreateSnatEntryArgs{ + RegionId: getRegion(d, meta), + SnatTableId: d.Get("snat_table_id").(string), + SourceVSwitchId: d.Get("source_vswitch_id").(string), + SnatIp: d.Get("snat_ip").(string), + } + + resp, err := conn.CreateSnatEntry(args) + if err != nil { + return fmt.Errorf("CreateSnatEntry got error: %#v", err) + } + + d.SetId(resp.SnatEntryId) + d.Set("snat_table_id", d.Get("snat_table_id").(string)) + + return resourceAliyunSnatEntryRead(d, meta) +} + +func resourceAliyunSnatEntryRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AliyunClient) + + snatEntry, err := client.DescribeSnatEntry(d.Get("snat_table_id").(string), d.Id()) + + if err != nil { + if notFoundError(err) { + return nil + } + return err + } + + d.Set("snat_table_id", snatEntry.SnatTableId) + d.Set("source_vswitch_id", snatEntry.SourceVSwitchId) + d.Set("snat_ip", snatEntry.SnatIp) + + return nil +} + +func resourceAliyunSnatEntryUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AliyunClient) + conn := client.vpcconn + + snatEntry, err := client.DescribeSnatEntry(d.Get("snat_table_id").(string), d.Id()) + if err != nil { + return err + } + + d.Partial(true) + attributeUpdate := false + args := &ecs.ModifySnatEntryArgs{ + RegionId: getRegion(d, meta), + SnatTableId: snatEntry.SnatTableId, + SnatEntryId: snatEntry.SnatEntryId, + } + + if d.HasChange("snat_ip") { + d.SetPartial("snat_ip") + var snat_ip string + if v, ok := d.GetOk("snat_ip"); ok { + snat_ip = v.(string) + } else { + return fmt.Errorf("cann't change snap_ip to empty string") + } + args.SnatIp = snat_ip + + attributeUpdate = true + } + + if attributeUpdate { + if err := conn.ModifySnatEntry(args); err != nil { + return err + } + } + + d.Partial(false) + + return resourceAliyunSnatEntryRead(d, meta) +} + +func resourceAliyunSnatEntryDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AliyunClient) + conn := client.vpcconn + + snatEntryId := d.Id() + snatTableId := d.Get("snat_table_id").(string) + + args := &ecs.DeleteSnatEntryArgs{ + RegionId: getRegion(d, meta), + SnatTableId: snatTableId, + SnatEntryId: snatEntryId, + } + + if err := conn.DeleteSnatEntry(args); err != nil { + return err + } + + return nil +} diff --git a/builtin/providers/alicloud/resource_alicloud_snat_test.go b/builtin/providers/alicloud/resource_alicloud_snat_test.go new file mode 100644 index 000000000..673ff59dd --- /dev/null +++ b/builtin/providers/alicloud/resource_alicloud_snat_test.go @@ -0,0 +1,180 @@ +package alicloud + +import ( + "fmt" + "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ecs" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "testing" +) + +func TestAccAlicloudSnat_basic(t *testing.T) { + var snat ecs.SnatEntrySetType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_snat_entry.foo", + Providers: testAccProviders, + CheckDestroy: testAccCheckSnatEntryDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccSnatEntryConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckSnatEntryExists( + "alicloud_snat_entry.foo", &snat), + ), + }, + resource.TestStep{ + Config: testAccSnatEntryUpdate, + Check: resource.ComposeTestCheckFunc( + testAccCheckSnatEntryExists( + "alicloud_snat_entry.foo", &snat), + ), + }, + }, + }) + +} + +func testAccCheckSnatEntryDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*AliyunClient) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "alicloud_snat_entry" { + continue + } + + // Try to find the Snat entry + instance, err := client.DescribeSnatEntry(rs.Primary.Attributes["snat_table_id"], rs.Primary.ID) + + //this special deal cause the DescribeSnatEntry can't find the records would be throw "cant find the snatTable error" + if instance.SnatEntryId == "" { + return nil + } + + if instance.SnatEntryId != "" { + return fmt.Errorf("Snat entry still exist") + } + + if err != nil { + // Verify the error is what we want + e, _ := err.(*common.Error) + + if !notFoundError(e) { + return err + } + } + + } + + return nil +} + +func testAccCheckSnatEntryExists(n string, snat *ecs.SnatEntrySetType) 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 SnatEntry ID is set") + } + + client := testAccProvider.Meta().(*AliyunClient) + instance, err := client.DescribeSnatEntry(rs.Primary.Attributes["snat_table_id"], rs.Primary.ID) + + if err != nil { + return err + } + if instance.SnatEntryId == "" { + return fmt.Errorf("SnatEntry not found") + } + + *snat = instance + return nil + } +} + +const testAccSnatEntryConfig = ` +data "alicloud_zones" "default" { + "available_resource_creation"= "VSwitch" +} + +resource "alicloud_vpc" "foo" { + name = "tf_test_foo" + cidr_block = "172.16.0.0/12" +} + +resource "alicloud_vswitch" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "172.16.0.0/21" + availability_zone = "${data.alicloud_zones.default.zones.2.id}" +} + +resource "alicloud_nat_gateway" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + spec = "Small" + name = "test_foo" + bandwidth_packages = [{ + ip_count = 2 + bandwidth = 5 + zone = "${data.alicloud_zones.default.zones.2.id}" + },{ + ip_count = 1 + bandwidth = 6 + zone = "${data.alicloud_zones.default.zones.2.id}" + }] + depends_on = [ + "alicloud_vswitch.foo"] +} +resource "alicloud_snat_entry" "foo"{ + snat_table_id = "${alicloud_nat_gateway.foo.snat_table_ids}" + source_vswitch_id = "${alicloud_vswitch.foo.id}" + snat_ip = "${alicloud_nat_gateway.foo.bandwidth_packages.0.public_ip_addresses}" +} +` + +const testAccSnatEntryUpdate = ` +data "alicloud_zones" "default" { + "available_resource_creation"= "VSwitch" +} + +resource "alicloud_vpc" "foo" { + name = "tf_test_foo" + cidr_block = "172.16.0.0/12" +} + +resource "alicloud_vswitch" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + cidr_block = "172.16.0.0/21" + availability_zone = "${data.alicloud_zones.default.zones.2.id}" +} + +resource "alicloud_nat_gateway" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + spec = "Small" + name = "test_foo" + bandwidth_packages = [{ + ip_count = 2 + bandwidth = 5 + zone = "${data.alicloud_zones.default.zones.2.id}" + },{ + ip_count = 1 + bandwidth = 6 + zone = "${data.alicloud_zones.default.zones.2.id}" + }] + depends_on = [ + "alicloud_vswitch.foo"] +} +resource "alicloud_snat_entry" "foo"{ + snat_table_id = "${alicloud_nat_gateway.foo.snat_table_ids}" + source_vswitch_id = "${alicloud_vswitch.foo.id}" + snat_ip = "${alicloud_nat_gateway.foo.bandwidth_packages.1.public_ip_addresses}" +} +` diff --git a/builtin/providers/alicloud/resource_alicloud_vpc.go b/builtin/providers/alicloud/resource_alicloud_vpc.go index e59e3b53b..7418395fd 100644 --- a/builtin/providers/alicloud/resource_alicloud_vpc.go +++ b/builtin/providers/alicloud/resource_alicloud_vpc.go @@ -86,7 +86,7 @@ func resourceAliyunVpcCreate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Timeout when WaitForVpcAvailable") } - return resourceAliyunVpcRead(d, meta) + return resourceAliyunVpcUpdate(d, meta) } func resourceAliyunVpcRead(d *schema.ResourceData, meta interface{}) error { @@ -144,7 +144,7 @@ func resourceAliyunVpcUpdate(d *schema.ResourceData, meta interface{}) error { d.Partial(false) - return nil + return resourceAliyunVpcRead(d, meta) } func resourceAliyunVpcDelete(d *schema.ResourceData, meta interface{}) error { diff --git a/builtin/providers/alicloud/resource_alicloud_vswitch.go b/builtin/providers/alicloud/resource_alicloud_vswitch.go index 74d4c6a88..d4149b9ca 100644 --- a/builtin/providers/alicloud/resource_alicloud_vswitch.go +++ b/builtin/providers/alicloud/resource_alicloud_vswitch.go @@ -68,7 +68,7 @@ func resourceAliyunSwitchCreate(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("WaitForVSwitchAvailable got a error: %s", err) } - return resourceAliyunSwitchRead(d, meta) + return resourceAliyunSwitchUpdate(d, meta) } func resourceAliyunSwitchRead(d *schema.ResourceData, meta interface{}) error { @@ -139,7 +139,7 @@ func resourceAliyunSwitchUpdate(d *schema.ResourceData, meta interface{}) error d.Partial(false) - return nil + return resourceAliyunSwitchRead(d, meta) } func resourceAliyunSwitchDelete(d *schema.ResourceData, meta interface{}) error { diff --git a/builtin/providers/alicloud/service_alicloud_ecs.go b/builtin/providers/alicloud/service_alicloud_ecs.go index 4ff0e5f04..79b6b07fb 100644 --- a/builtin/providers/alicloud/service_alicloud_ecs.go +++ b/builtin/providers/alicloud/service_alicloud_ecs.go @@ -131,7 +131,7 @@ func (client *AliyunClient) QueryInstancesById(id string) (instance *ecs.Instanc } if len(instances) == 0 { - return nil, common.GetClientErrorFromString(InstanceNotfound) + return nil, GetNotFoundErrorFromString(InstanceNotfound) } return &instances[0], nil @@ -244,7 +244,7 @@ func (client *AliyunClient) DescribeSecurityGroupRule(securityGroupId, direction return &p, nil } } - return nil, nil + return nil, GetNotFoundErrorFromString("Security group rule not found") } diff --git a/builtin/providers/alicloud/service_alicloud_ess.go b/builtin/providers/alicloud/service_alicloud_ess.go new file mode 100644 index 000000000..69d514ef2 --- /dev/null +++ b/builtin/providers/alicloud/service_alicloud_ess.go @@ -0,0 +1,167 @@ +package alicloud + +import ( + "github.com/denverdino/aliyungo/ess" +) + +func (client *AliyunClient) DescribeScalingGroupById(sgId string) (*ess.ScalingGroupItemType, error) { + args := ess.DescribeScalingGroupsArgs{ + RegionId: client.Region, + ScalingGroupId: []string{sgId}, + } + + sgs, _, err := client.essconn.DescribeScalingGroups(&args) + if err != nil { + return nil, err + } + + if len(sgs) == 0 { + return nil, GetNotFoundErrorFromString("Scaling group not found") + } + + return &sgs[0], nil +} + +func (client *AliyunClient) DeleteScalingGroupById(sgId string) error { + args := ess.DeleteScalingGroupArgs{ + ScalingGroupId: sgId, + ForceDelete: true, + } + + _, err := client.essconn.DeleteScalingGroup(&args) + return err +} + +func (client *AliyunClient) DescribeScalingConfigurationById(sgId, configId string) (*ess.ScalingConfigurationItemType, error) { + args := ess.DescribeScalingConfigurationsArgs{ + RegionId: client.Region, + ScalingGroupId: sgId, + ScalingConfigurationId: []string{configId}, + } + + cs, _, err := client.essconn.DescribeScalingConfigurations(&args) + if err != nil { + return nil, err + } + + if len(cs) == 0 { + return nil, GetNotFoundErrorFromString("Scaling configuration not found") + } + + return &cs[0], nil +} + +func (client *AliyunClient) ActiveScalingConfigurationById(sgId, configId string) error { + args := ess.ModifyScalingGroupArgs{ + ScalingGroupId: sgId, + ActiveScalingConfigurationId: configId, + } + + _, err := client.essconn.ModifyScalingGroup(&args) + return err +} + +func (client *AliyunClient) EnableScalingConfigurationById(sgId, configId string, ids []string) error { + args := ess.EnableScalingGroupArgs{ + ScalingGroupId: sgId, + ActiveScalingConfigurationId: configId, + } + + if len(ids) > 0 { + args.InstanceId = ids + } + + _, err := client.essconn.EnableScalingGroup(&args) + return err +} + +func (client *AliyunClient) DisableScalingConfigurationById(sgId string) error { + args := ess.DisableScalingGroupArgs{ + ScalingGroupId: sgId, + } + + _, err := client.essconn.DisableScalingGroup(&args) + return err +} + +func (client *AliyunClient) DeleteScalingConfigurationById(sgId, configId string) error { + args := ess.DeleteScalingConfigurationArgs{ + ScalingGroupId: sgId, + ScalingConfigurationId: configId, + } + + _, err := client.essconn.DeleteScalingConfiguration(&args) + return err +} + +// Flattens an array of datadisk into a []map[string]interface{} +func flattenDataDiskMappings(list []ess.DataDiskItemType) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(list)) + for _, i := range list { + l := map[string]interface{}{ + "size": i.Size, + "category": i.Category, + "snapshot_id": i.SnapshotId, + "device": i.Device, + } + result = append(result, l) + } + return result +} + +func (client *AliyunClient) DescribeScalingRuleById(sgId, ruleId string) (*ess.ScalingRuleItemType, error) { + args := ess.DescribeScalingRulesArgs{ + RegionId: client.Region, + ScalingGroupId: sgId, + ScalingRuleId: []string{ruleId}, + } + + cs, _, err := client.essconn.DescribeScalingRules(&args) + if err != nil { + return nil, err + } + + if len(cs) == 0 { + return nil, GetNotFoundErrorFromString("Scaling rule not found") + } + + return &cs[0], nil +} + +func (client *AliyunClient) DeleteScalingRuleById(ruleId string) error { + args := ess.DeleteScalingRuleArgs{ + RegionId: client.Region, + ScalingRuleId: ruleId, + } + + _, err := client.essconn.DeleteScalingRule(&args) + return err +} + +func (client *AliyunClient) DescribeScheduleById(scheduleId string) (*ess.ScheduledTaskItemType, error) { + args := ess.DescribeScheduledTasksArgs{ + RegionId: client.Region, + ScheduledTaskId: []string{scheduleId}, + } + + cs, _, err := client.essconn.DescribeScheduledTasks(&args) + if err != nil { + return nil, err + } + + if len(cs) == 0 { + return nil, GetNotFoundErrorFromString("Schedule not found") + } + + return &cs[0], nil +} + +func (client *AliyunClient) DeleteScheduleById(scheduleId string) error { + args := ess.DeleteScheduledTaskArgs{ + RegionId: client.Region, + ScheduledTaskId: scheduleId, + } + + _, err := client.essconn.DeleteScheduledTask(&args) + return err +} diff --git a/builtin/providers/alicloud/service_alicloud_rds.go b/builtin/providers/alicloud/service_alicloud_rds.go index 903374fe6..700a5d138 100644 --- a/builtin/providers/alicloud/service_alicloud_rds.go +++ b/builtin/providers/alicloud/service_alicloud_rds.go @@ -6,7 +6,20 @@ import ( "strings" ) -// when getInstance is empty, then throw InstanceNotfound error +// +// _______________ _______________ _______________ +// | | ______param______\ | | _____request_____\ | | +// | Business | | Service | | SDK/API | +// | | __________________ | | __________________ | | +// |______________| \ (obj, err) |______________| \ (status, cont) |______________| +// | | +// |A. {instance, nil} |a. {200, content} +// |B. {nil, error} |b. {200, nil} +// |c. {4xx, nil} +// +// The API return 200 for resource not found. +// When getInstance is empty, then throw InstanceNotfound error. +// That the business layer only need to check error. func (client *AliyunClient) DescribeDBInstanceById(id string) (instance *rds.DBInstanceAttribute, err error) { arrtArgs := rds.DescribeDBInstancesArgs{ DBInstanceId: id, @@ -19,7 +32,7 @@ func (client *AliyunClient) DescribeDBInstanceById(id string) (instance *rds.DBI attr := resp.Items.DBInstanceAttribute if len(attr) <= 0 { - return nil, common.GetClientErrorFromString(InstanceNotfound) + return nil, GetNotFoundErrorFromString("DB instance not found") } return &attr[0], nil @@ -164,13 +177,10 @@ func (client *AliyunClient) GetSecurityIps(instanceId string) ([]string, error) if err != nil { return nil, err } - ips := "" - for i, ip := range arr { - if i == 0 { - ips += ip.SecurityIPList - } else { - ips += COMMA_SEPARATED + ip.SecurityIPList - } + var ips, separator string + for _, ip := range arr { + ips += separator + ip.SecurityIPList + separator = COMMA_SEPARATED } return strings.Split(ips, COMMA_SEPARATED), nil } diff --git a/builtin/providers/alicloud/service_alicloud_vpc.go b/builtin/providers/alicloud/service_alicloud_vpc.go index 775fe112c..491ab034f 100644 --- a/builtin/providers/alicloud/service_alicloud_vpc.go +++ b/builtin/providers/alicloud/service_alicloud_vpc.go @@ -32,6 +32,7 @@ func (client *AliyunClient) DescribeNatGateway(natGatewayId string) (*ecs.NatGat } natGateways, _, err := client.vpcconn.DescribeNatGateways(args) + //fmt.Println("natGateways %#v", natGateways) if err != nil { return nil, err } @@ -64,6 +65,78 @@ func (client *AliyunClient) DescribeVpc(vpcId string) (*ecs.VpcSetType, error) { return &vpcs[0], nil } +func (client *AliyunClient) DescribeSnatEntry(snatTableId string, snatEntryId string) (ecs.SnatEntrySetType, error) { + + var resultSnat ecs.SnatEntrySetType + + args := &ecs.DescribeSnatTableEntriesArgs{ + RegionId: client.Region, + SnatTableId: snatTableId, + } + + snatEntries, _, err := client.vpcconn.DescribeSnatTableEntries(args) + + //this special deal cause the DescribeSnatEntry can't find the records would be throw "cant find the snatTable error" + //so judge the snatEntries length priority + if len(snatEntries) == 0 { + return resultSnat, common.GetClientErrorFromString(InstanceNotfound) + } + + if err != nil { + return resultSnat, err + } + + findSnat := false + + for _, snat := range snatEntries { + if snat.SnatEntryId == snatEntryId { + resultSnat = snat + findSnat = true + } + } + if !findSnat { + return resultSnat, common.GetClientErrorFromString(NotFindSnatEntryBySnatId) + } + + return resultSnat, nil +} + +func (client *AliyunClient) DescribeForwardEntry(forwardTableId string, forwardEntryId string) (ecs.ForwardTableEntrySetType, error) { + + var resultFoward ecs.ForwardTableEntrySetType + + args := &ecs.DescribeForwardTableEntriesArgs{ + RegionId: client.Region, + ForwardTableId: forwardTableId, + } + + forwardEntries, _, err := client.vpcconn.DescribeForwardTableEntries(args) + + //this special deal cause the DescribeSnatEntry can't find the records would be throw "cant find the snatTable error" + //so judge the snatEntries length priority + if len(forwardEntries) == 0 { + return resultFoward, common.GetClientErrorFromString(InstanceNotfound) + } + + findForward := false + + for _, forward := range forwardEntries { + if forward.ForwardEntryId == forwardEntryId { + resultFoward = forward + findForward = true + } + } + if !findForward { + return resultFoward, common.GetClientErrorFromString(NotFindForwardEntryByForwardId) + } + + if err != nil { + return resultFoward, err + } + + return resultFoward, nil +} + // describe vswitch by param filters func (client *AliyunClient) QueryVswitches(args *ecs.DescribeVSwitchesArgs) (vswitches []ecs.VSwitchSetType, err error) { vsws, _, err := client.ecsconn.DescribeVSwitches(args) @@ -130,7 +203,7 @@ func (client *AliyunClient) QueryRouteEntry(routeTableId, cidrBlock, nextHopType return &e, nil } } - return nil, nil + return nil, GetNotFoundErrorFromString("Vpc router entry not found") } func (client *AliyunClient) GetVpcIdByVSwitchId(vswitchId string) (vpcId string, err error) { diff --git a/builtin/providers/alicloud/struct_security_groups.go b/builtin/providers/alicloud/struct_security_groups.go deleted file mode 100644 index 678f68f7d..000000000 --- a/builtin/providers/alicloud/struct_security_groups.go +++ /dev/null @@ -1,11 +0,0 @@ -package alicloud - -// Takes the result of flatmap.Expand for an array of strings -// and returns a []string -func expandStringList(configured []interface{}) []string { - vs := make([]string, 0, len(configured)) - for _, v := range configured { - vs = append(vs, v.(string)) - } - return vs -} diff --git a/builtin/providers/alicloud/validators.go b/builtin/providers/alicloud/validators.go index 9687e68e8..4c3c82f3e 100644 --- a/builtin/providers/alicloud/validators.go +++ b/builtin/providers/alicloud/validators.go @@ -18,7 +18,7 @@ func validateInstancePort(v interface{}, k string) (ws []string, errors []error) value := v.(int) if value < 1 || value > 65535 { errors = append(errors, fmt.Errorf( - "%q must be a valid instance port between 1 and 65535", + "%q must be a valid port between 1 and 65535", k)) return } @@ -26,8 +26,8 @@ func validateInstancePort(v interface{}, k string) (ws []string, errors []error) } func validateInstanceProtocol(v interface{}, k string) (ws []string, errors []error) { - protocal := v.(string) - if !isProtocalValid(protocal) { + protocol := v.(string) + if !isProtocolValid(protocol) { errors = append(errors, fmt.Errorf( "%q is an invalid value. Valid values are either http, https, tcp or udp", k)) @@ -282,9 +282,9 @@ func validateInternetChargeType(v interface{}, k string) (ws []string, errors [] func validateInternetMaxBandWidthOut(v interface{}, k string) (ws []string, errors []error) { value := v.(int) - if value < 1 || value > 100 { + if value < 0 || value > 100 { errors = append(errors, fmt.Errorf( - "%q must be a valid internet bandwidth out between 1 and 1000", + "%q must be a valid internet bandwidth out between 0 and 100", k)) return } @@ -565,3 +565,14 @@ func validateRegion(v interface{}, k string) (ws []string, errors []error) { } return } + +func validateForwardPort(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + if value != "any" { + valueConv, err := strconv.Atoi(value) + if err != nil || valueConv < 1 || valueConv > 65535 { + errors = append(errors, fmt.Errorf("%q must be a valid port between 1 and 65535 or any ", k)) + } + } + return +} diff --git a/builtin/providers/alicloud/validators_test.go b/builtin/providers/alicloud/validators_test.go index 7d40de6b7..3160c496c 100644 --- a/builtin/providers/alicloud/validators_test.go +++ b/builtin/providers/alicloud/validators_test.go @@ -21,17 +21,17 @@ func TestValidateInstancePort(t *testing.T) { } func TestValidateInstanceProtocol(t *testing.T) { - validProtocals := []string{"http", "tcp", "https", "udp"} - for _, v := range validProtocals { - _, errors := validateInstanceProtocol(v, "instance_protocal") + validProtocols := []string{"http", "tcp", "https", "udp"} + for _, v := range validProtocols { + _, errors := validateInstanceProtocol(v, "instance_protocol") if len(errors) != 0 { t.Fatalf("%q should be a valid instance protocol: %q", v, errors) } } - invalidProtocals := []string{"HTTP", "abc", "ecmp", "dubbo"} - for _, v := range invalidProtocals { - _, errors := validateInstanceProtocol(v, "instance_protocal") + invalidProtocols := []string{"HTTP", "abc", "ecmp", "dubbo"} + for _, v := range invalidProtocols { + _, errors := validateInstanceProtocol(v, "instance_protocol") if len(errors) == 0 { t.Fatalf("%q should be an invalid instance protocol", v) } @@ -353,7 +353,7 @@ func TestValidateInternetMaxBandWidthOut(t *testing.T) { } } - invalidInternetMaxBandWidthOut := []int{-2, 0, 101, 123} + invalidInternetMaxBandWidthOut := []int{-2, 101, 123} for _, v := range invalidInternetMaxBandWidthOut { _, errors := validateInternetMaxBandWidthOut(v, "internet_max_bandwidth_out") if len(errors) == 0 { diff --git a/examples/alicloud-ess-scaling/README.md b/examples/alicloud-ess-scaling/README.md new file mode 100644 index 000000000..3d9d2abb3 --- /dev/null +++ b/examples/alicloud-ess-scaling/README.md @@ -0,0 +1,17 @@ +### ESS scaling configuration Example + +The example launches ESS scaling configuration, will create ECS instance automatic by system schedule. + +### Get up and running + +* Planning phase + + terraform plan + +* Apply phase + + terraform apply + +* Destroy + + terraform destroy \ No newline at end of file diff --git a/examples/alicloud-ess-scaling/main.tf b/examples/alicloud-ess-scaling/main.tf new file mode 100644 index 000000000..0f7575bc9 --- /dev/null +++ b/examples/alicloud-ess-scaling/main.tf @@ -0,0 +1,38 @@ +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} + +resource "alicloud_security_group" "sg" { + name = "${var.security_group_name}" + description = "tf-sg" +} + +resource "alicloud_security_group_rule" "ssh-in" { + type = "ingress" + ip_protocol = "tcp" + nic_type = "internet" + policy = "accept" + port_range = "22/22" + priority = 1 + security_group_id = "${alicloud_security_group.sg.id}" + cidr_ip = "0.0.0.0/0" +} + +resource "alicloud_ess_scaling_group" "scaling" { + min_size = "${var.scaling_min_size}" + max_size = "${var.scaling_max_size}" + scaling_group_name = "tf-scaling" + removal_policies = "${var.removal_policies}" + +} + +resource "alicloud_ess_scaling_configuration" "config" { + scaling_group_id = "${alicloud_ess_scaling_group.scaling.id}" + enable = "${var.enable}" + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "${var.ecs_instance_type}" + io_optimized = "optimized" + security_group_id = "${alicloud_security_group.sg.id}" +} \ No newline at end of file diff --git a/examples/alicloud-ess-scaling/outputs.tf b/examples/alicloud-ess-scaling/outputs.tf new file mode 100644 index 000000000..c4bfbb73e --- /dev/null +++ b/examples/alicloud-ess-scaling/outputs.tf @@ -0,0 +1,7 @@ +output "scaling_group_id" { + value = "${alicloud_ess_scaling_group.scaling.id}" +} + +output "configuration_id" { + value = "${alicloud_ess_scaling_configuration.config.id}" +} \ No newline at end of file diff --git a/examples/alicloud-ess-scaling/variables.tf b/examples/alicloud-ess-scaling/variables.tf new file mode 100644 index 000000000..11d2ef567 --- /dev/null +++ b/examples/alicloud-ess-scaling/variables.tf @@ -0,0 +1,24 @@ +variable "security_group_name" { + default = "tf-sg" +} + +variable "scaling_min_size" { + default = 1 +} + +variable "scaling_max_size" { + default = 1 +} + +variable "enable" { + default = true +} + +variable "removal_policies" { + type = "list" + default = ["OldestInstance", "NewestInstance"] +} + +variable "ecs_instance_type" { + default = "ecs.s2.large" +} \ No newline at end of file diff --git a/examples/alicloud-ess-schedule/README.md b/examples/alicloud-ess-schedule/README.md new file mode 100644 index 000000000..e606951b1 --- /dev/null +++ b/examples/alicloud-ess-schedule/README.md @@ -0,0 +1,17 @@ +### ESS scaling schedule Example + +The example launches ESS schedule task, which will create ECS by the schedule time. + +### Get up and running + +* Planning phase + + terraform plan + +* Apply phase + + terraform apply + +* Destroy + + terraform destroy \ No newline at end of file diff --git a/examples/alicloud-ess-schedule/main.tf b/examples/alicloud-ess-schedule/main.tf new file mode 100644 index 000000000..339ba670b --- /dev/null +++ b/examples/alicloud-ess-schedule/main.tf @@ -0,0 +1,51 @@ +data "alicloud_images" "ecs_image" { + most_recent = true + name_regex = "^centos_6\\w{1,5}[64].*" +} + +resource "alicloud_security_group" "sg" { + name = "${var.security_group_name}" + description = "tf-sg" +} + +resource "alicloud_security_group_rule" "ssh-in" { + type = "ingress" + ip_protocol = "tcp" + nic_type = "internet" + policy = "accept" + port_range = "22/22" + priority = 1 + security_group_id = "${alicloud_security_group.sg.id}" + cidr_ip = "0.0.0.0/0" +} + +resource "alicloud_ess_scaling_group" "scaling" { + min_size = "${var.scaling_min_size}" + max_size = "${var.scaling_max_size}" + scaling_group_name = "tf-scaling" + removal_policies = "${var.removal_policies}" + +} + +resource "alicloud_ess_scaling_configuration" "config" { + scaling_group_id = "${alicloud_ess_scaling_group.scaling.id}" + enable = "${var.enable}" + + image_id = "${data.alicloud_images.ecs_image.images.0.id}" + instance_type = "${var.ecs_instance_type}" + io_optimized = "optimized" + security_group_id = "${alicloud_security_group.sg.id}" +} + +resource "alicloud_ess_scaling_rule" "rule" { + scaling_group_id = "${alicloud_ess_scaling_group.scaling.id}" + adjustment_type = "TotalCapacity" + adjustment_value = "${var.rule_adjust_size}" + cooldown = 60 +} + +resource "alicloud_ess_schedule" "run" { + scheduled_action = "${alicloud_ess_scaling_rule.rule.ari}" + launch_time = "${var.schedule_launch_time}" + scheduled_task_name = "tf-run" +} \ No newline at end of file diff --git a/examples/alicloud-ess-schedule/outputs.tf b/examples/alicloud-ess-schedule/outputs.tf new file mode 100644 index 000000000..1d48aabfd --- /dev/null +++ b/examples/alicloud-ess-schedule/outputs.tf @@ -0,0 +1,11 @@ +output "scaling_group_id" { + value = "${alicloud_ess_scaling_group.scaling.id}" +} + +output "configuration_id" { + value = "${alicloud_ess_scaling_configuration.config.id}" +} + +output "configuration_ari" { + value = "${alicloud_ess_scaling_configuration.config.ari}" +} \ No newline at end of file diff --git a/examples/alicloud-ess-schedule/variables.tf b/examples/alicloud-ess-schedule/variables.tf new file mode 100644 index 000000000..fb95b6bee --- /dev/null +++ b/examples/alicloud-ess-schedule/variables.tf @@ -0,0 +1,32 @@ +variable "security_group_name" { + default = "tf-sg" +} + +variable "scaling_min_size" { + default = 1 +} + +variable "scaling_max_size" { + default = 1 +} + +variable "enable" { + default = true +} + +variable "removal_policies" { + type = "list" + default = ["OldestInstance", "NewestInstance"] +} + +variable "ecs_instance_type" { + default = "ecs.s2.large" +} + +variable "rule_adjust_size" { + default = 3 +} + +variable "schedule_launch_time" { + default = "2017-04-01T01:59Z" +} \ No newline at end of file diff --git a/examples/alicloud-vpc-snat/main.tf b/examples/alicloud-vpc-snat/main.tf new file mode 100644 index 000000000..1f204432a --- /dev/null +++ b/examples/alicloud-vpc-snat/main.tf @@ -0,0 +1,87 @@ +provider "alicloud" { + region = "cn-hangzhou" +} + +data "alicloud_instance_types" "1c2g" { + cpu_core_count = 1 + memory_size = 2 + instance_type_family = "ecs.n1" +} + +data "alicloud_zones" "default" { + "available_instance_type"= "${data.alicloud_instance_types.1c2g.instance_types.0.id}" + "available_disk_category"= "${var.disk_category}" +} + +resource "alicloud_vpc" "default" { + name = "tf_vpc" + cidr_block = "${var.vpc_cidr}" +} + +resource "alicloud_vswitch" "default" { + vpc_id = "${alicloud_vpc.default.id}" + cidr_block = "${var.vswitch_cidr}" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" +} + +resource "alicloud_nat_gateway" "default" { + vpc_id = "${alicloud_vpc.default.id}" + spec = "Small" + name = "test_foo" + bandwidth_packages = [{ + ip_count = 2 + bandwidth = 5 + zone = "${data.alicloud_zones.default.zones.0.id}" + }] + depends_on = [ + "alicloud_vswitch.default"] +} +resource "alicloud_snat_entry" "default"{ + snat_table_id = "${alicloud_nat_gateway.default.snat_table_ids}" + source_vswitch_id = "${alicloud_vswitch.default.id}" + snat_ip = "${element(split(",", alicloud_nat_gateway.default.bandwidth_packages.0.public_ip_addresses),0)}" +} + +resource "alicloud_forward_entry" "default"{ + forward_table_id = "${alicloud_nat_gateway.default.forward_table_ids}" + external_ip = "${element(split(",", alicloud_nat_gateway.default.bandwidth_packages.0.public_ip_addresses),1)}" + external_port = "80" + ip_protocol = "tcp" + internal_ip = "${alicloud_instance.default.private_ip}" + internal_port = "8080" +} + +resource "alicloud_security_group" "sg" { + name = "tf_sg" + description = "tf_sg" + vpc_id = "${alicloud_vpc.default.id}" +} + +resource "alicloud_security_group_rule" "http-in" { + type = "ingress" + ip_protocol = "tcp" + nic_type = "intranet" + policy = "accept" + port_range = "80/80" + priority = 1 + security_group_id = "${alicloud_security_group.sg.id}" + cidr_ip = "0.0.0.0/0" +} + +resource "alicloud_instance" "default" { + # cn-beijing + availability_zone = "${data.alicloud_zones.default.zones.0.id}" + security_groups = ["${alicloud_security_group.sg.id}"] + + vswitch_id = "${alicloud_vswitch.default.id}" + + # series II + instance_charge_type = "PostPaid" + instance_type = "${var.instance_type}" + internet_max_bandwidth_out = 0 + io_optimized = "${var.io_optimized}" + + system_disk_category = "cloud_efficiency" + image_id = "${var.image_id}" + instance_name = "tf_vpc_snat" +} \ No newline at end of file diff --git a/examples/alicloud-vpc-snat/ouputs.tf b/examples/alicloud-vpc-snat/ouputs.tf new file mode 100644 index 000000000..f9a55914f --- /dev/null +++ b/examples/alicloud-vpc-snat/ouputs.tf @@ -0,0 +1,7 @@ +output "instance_id" { + value = "${alicloud_instance.default.id}" +} + +output "bindwidth_package_ip" { + value = "${alicloud_nat_gateway.default.bandwidth_packages.0.public_ip_addresses}" +} diff --git a/examples/alicloud-vpc-snat/variables.tf b/examples/alicloud-vpc-snat/variables.tf new file mode 100644 index 000000000..9e9eb76db --- /dev/null +++ b/examples/alicloud-vpc-snat/variables.tf @@ -0,0 +1,22 @@ + +variable "vpc_cidr" { + default = "10.1.0.0/21" +} +variable "vswitch_cidr" { + default = "10.1.1.0/24" +} +variable "rule_policy" { + default = "accept" +} +variable "instance_type" { + default = "ecs.n1.small" +} +variable "image_id" { + default = "ubuntu_140405_64_40G_cloudinit_20161115.vhd" +} +variable "io_optimized" { + default = "optimized" +} +variable "disk_category"{ + default = "cloud_efficiency" +} \ No newline at end of file diff --git a/vendor/github.com/denverdino/aliyungo/common/client.go b/vendor/github.com/denverdino/aliyungo/common/client.go index 69a9c3d1e..d186ebd82 100755 --- a/vendor/github.com/denverdino/aliyungo/common/client.go +++ b/vendor/github.com/denverdino/aliyungo/common/client.go @@ -13,6 +13,14 @@ import ( "github.com/denverdino/aliyungo/util" ) +// RemovalPolicy.N add index to array item +// RemovalPolicy=["a", "b"] => RemovalPolicy.1="a" RemovalPolicy.2="b" +type FlattenArray []string + +// string contains underline which will be replaced with dot +// SystemDisk_Category => SystemDisk.Category +type UnderlineString string + // A Client represents a client of ECS services type Client struct { AccessKeyId string //Access Key Id @@ -167,6 +175,75 @@ func (client *Client) Invoke(action string, args interface{}, response interface return nil } +// Invoke sends the raw HTTP request for ECS services +func (client *Client) InvokeByFlattenMethod(action string, args interface{}, response interface{}) error { + + request := Request{} + request.init(client.version, action, client.AccessKeyId) + + query := util.ConvertToQueryValues(request) + + util.SetQueryValueByFlattenMethod(args, &query) + + // Sign request + signature := util.CreateSignatureForRequest(ECSRequestMethod, &query, client.AccessKeySecret) + + // Generate the request URL + requestURL := client.endpoint + "?" + query.Encode() + "&Signature=" + url.QueryEscape(signature) + + httpReq, err := http.NewRequest(ECSRequestMethod, requestURL, nil) + + if err != nil { + return GetClientError(err) + } + + // TODO move to util and add build val flag + httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo) + + t0 := time.Now() + httpResp, err := client.httpClient.Do(httpReq) + t1 := time.Now() + if err != nil { + return GetClientError(err) + } + statusCode := httpResp.StatusCode + + if client.debug { + log.Printf("Invoke %s %s %d (%v)", ECSRequestMethod, requestURL, statusCode, t1.Sub(t0)) + } + + defer httpResp.Body.Close() + body, err := ioutil.ReadAll(httpResp.Body) + + if err != nil { + return GetClientError(err) + } + + if client.debug { + var prettyJSON bytes.Buffer + err = json.Indent(&prettyJSON, body, "", " ") + log.Println(string(prettyJSON.Bytes())) + } + + if statusCode >= 400 && statusCode <= 599 { + errorResponse := ErrorResponse{} + err = json.Unmarshal(body, &errorResponse) + ecsError := &Error{ + ErrorResponse: errorResponse, + StatusCode: statusCode, + } + return ecsError + } + + err = json.Unmarshal(body, response) + //log.Printf("%++v", response) + if err != nil { + return GetClientError(err) + } + + return nil +} + // Invoke sends the raw HTTP request for ECS services //改进了一下上面那个方法,可以使用各种Http方法 //2017.1.30 增加了一个path参数,用来拓展访问的地址 diff --git a/vendor/github.com/denverdino/aliyungo/common/endpoints.xml b/vendor/github.com/denverdino/aliyungo/common/endpoints.xml index 8e781ac46..4079bcd2b 100644 --- a/vendor/github.com/denverdino/aliyungo/common/endpoints.xml +++ b/vendor/github.com/denverdino/aliyungo/common/endpoints.xml @@ -32,7 +32,6 @@ Smssms.aliyuncs.com Jaqjaq.aliyuncs.com HPChpc.aliyuncs.com - Kmskms.cn-hangzhou.aliyuncs.com Locationlocation.aliyuncs.com ChargingServicechargingservice.aliyuncs.com Msgmsg-inner.aliyuncs.com @@ -63,11 +62,9 @@ PTSpts.aliyuncs.com Qualitycheckqualitycheck.aliyuncs.com M-kvstorem-kvstore.aliyuncs.com - CloudAPIapigateway.cn-hangzhou.aliyuncs.com HighDDosyd-highddos-cn-hangzhou.aliyuncs.com CmsSiteMonitorsitemonitor.aliyuncs.com Rdsrds.aliyuncs.com - Mtsmts.cn-hangzhou.aliyuncs.com BatchComputebatchCompute.aliyuncs.com CFcf.aliyuncs.com Drdsdrds.aliyuncs.com @@ -127,7 +124,7 @@ Smssms.aliyuncs.com Jaqjaq.aliyuncs.com CScs.aliyuncs.com - Kmskms.cn-hangzhou.aliyuncs.com + Kmskms.cn-hongkong.aliyuncs.com Locationlocation.aliyuncs.com Msgmsg-inner.aliyuncs.com ChargingServicechargingservice.aliyuncs.com @@ -158,11 +155,11 @@ Qualitycheckqualitycheck.aliyuncs.com Bssbss.aliyuncs.com Ubsmsubsms.aliyuncs.com - CloudAPIapigateway.cn-hangzhou.aliyuncs.com + CloudAPIapigateway.cn-hongkong.aliyuncs.com Stssts.aliyuncs.com CmsSiteMonitorsitemonitor.aliyuncs.com Aceace.cn-hangzhou.aliyuncs.com - Mtsmts.cn-hangzhou.aliyuncs.com + Mtsmts.cn-hongkong.aliyuncs.com Location-innerlocation-inner.aliyuncs.com CFcf.aliyuncs.com Acsacs.aliyun-inc.com @@ -235,7 +232,6 @@ Smssms.aliyuncs.com Drdsdrds.aliyuncs.com HPChpc.aliyuncs.com - Kmskms.cn-hangzhou.aliyuncs.com Locationlocation.aliyuncs.com Msgmsg-inner.aliyuncs.com ChargingServicechargingservice.aliyuncs.com @@ -265,9 +261,8 @@ Qualitycheckqualitycheck.aliyuncs.com Bssbss.aliyuncs.com M-kvstorem-kvstore.aliyuncs.com - CloudAPIapigateway.cn-hangzhou.aliyuncs.com Aceace.cn-hangzhou.aliyuncs.com - Mtsmts.cn-hangzhou.aliyuncs.com + Mtsmts.cn-qingdao.aliyuncs.com CFcf.aliyuncs.com Httpdnshttpdns-api.aliyuncs.com Location-innerlocation-inner.aliyuncs.com @@ -330,6 +325,7 @@ cn-shanghai + ARMSarms.cn-shanghai.aliyuncs.com Riskrisk-cn-hangzhou.aliyuncs.com COScos.aliyuncs.com HPChpc.aliyuncs.com @@ -371,11 +367,11 @@ Qualitycheckqualitycheck.aliyuncs.com M-kvstorem-kvstore.aliyuncs.com Apigatewayapigateway.cn-shanghai.aliyuncs.com - CloudAPIapigateway.cn-hangzhou.aliyuncs.com + CloudAPIapigateway.cn-shanghai.aliyuncs.com Stssts.aliyuncs.com Vpcvpc.aliyuncs.com Aceace.cn-hangzhou.aliyuncs.com - Mtsmts.cn-hangzhou.aliyuncs.com + Mtsmts.cn-shanghai.aliyuncs.com Ddsmongodb.aliyuncs.com CFcf.aliyuncs.com Acsacs.aliyun-inc.com @@ -403,6 +399,7 @@ Essess.aliyuncs.com Ossoss-cn-shanghai.aliyuncs.com YundunDdosinner-yundun-ddos.cn-hangzhou.aliyuncs.com + vodvod.cn-shanghai.aliyuncs.com @@ -419,7 +416,6 @@ Smssms.aliyuncs.com Salessales.cn-hangzhou.aliyuncs.com HPChpc.aliyuncs.com - Kmskms.cn-hangzhou.aliyuncs.com Locationlocation.aliyuncs.com Msgmsg-inner.aliyuncs.com ChargingServicechargingservice.aliyuncs.com @@ -447,10 +443,9 @@ PTSpts.aliyuncs.com Qualitycheckqualitycheck.aliyuncs.com M-kvstorem-kvstore.aliyuncs.com - CloudAPIapigateway.cn-hangzhou.aliyuncs.com Stssts.aliyuncs.com Aceace.cn-hangzhou.aliyuncs.com - Mtsmts.cn-hangzhou.aliyuncs.com + Mtsmts.cn-shenzhen.aliyuncs.com CFcf.aliyuncs.com Httpdnshttpdns-api.aliyuncs.com Greengreen.aliyuncs.com @@ -504,7 +499,6 @@ Jaqjaq.aliyuncs.com Pushcloudpush.aliyuncs.com Alidnsalidns.aliyuncs.com - Kmskms.cn-hangzhou.aliyuncs.com Locationlocation.aliyuncs.com Msgmsg-inner.aliyuncs.com ChargingServicechargingservice.aliyuncs.com @@ -534,11 +528,10 @@ PTSpts.aliyuncs.com Qualitycheckqualitycheck.aliyuncs.com Ubsmsubsms.aliyuncs.com - CloudAPIapigateway.cn-hangzhou.aliyuncs.com HighDDosyd-highddos-cn-hangzhou.aliyuncs.com CmsSiteMonitorsitemonitor.aliyuncs.com Rdsrds.aliyuncs.com - Mtsmts.cn-hangzhou.aliyuncs.com + Mtsmts.us-west-1.aliyuncs.com CFcf.aliyuncs.com Acsacs.aliyun-inc.com Httpdnshttpdns-api.aliyuncs.com @@ -579,7 +572,6 @@ Smssms.aliyuncs.com Drdsdrds.aliyuncs.com HPChpc.aliyuncs.com - Kmskms.cn-hangzhou.aliyuncs.com Locationlocation.aliyuncs.com ChargingServicechargingservice.aliyuncs.com Msgmsg-inner.aliyuncs.com @@ -610,10 +602,9 @@ PTSpts.aliyuncs.com Qualitycheckqualitycheck.aliyuncs.com Ubsmsubsms.aliyuncs.com - CloudAPIapigateway.cn-hangzhou.aliyuncs.com HighDDosyd-highddos-cn-hangzhou.aliyuncs.com Rdsrds.aliyuncs.com - Mtsmts.cn-hangzhou.aliyuncs.com + Mtsmts.cn-shanghai.aliyuncs.com CFcf.aliyuncs.com Httpdnshttpdns-api.aliyuncs.com Location-innerlocation-inner.aliyuncs.com @@ -652,6 +643,7 @@ cn-hangzhou + ARMSarms.cn-hangzhou.aliyuncs.com CScs.aliyuncs.com COScos.aliyuncs.com Essess.aliyuncs.com @@ -743,7 +735,6 @@ Smssms.aliyuncs.com Drdsdrds.aliyuncs.com CScs.aliyuncs.com - Kmskms.cn-hangzhou.aliyuncs.com Locationlocation.aliyuncs.com ChargingServicechargingservice.aliyuncs.com Msgmsg-inner.aliyuncs.com @@ -774,10 +765,9 @@ PTSpts.aliyuncs.com Qualitycheckqualitycheck.aliyuncs.com Ubsmsubsms.aliyuncs.com - CloudAPIapigateway.cn-hangzhou.aliyuncs.com Stssts.aliyuncs.com Rdsrds.aliyuncs.com - Mtsmts.cn-hangzhou.aliyuncs.com + Mtsmts.cn-beijing.aliyuncs.com Location-innerlocation-inner.aliyuncs.com CFcf.aliyuncs.com Httpdnshttpdns-api.aliyuncs.com @@ -819,6 +809,7 @@ cn-shenzhen + ARMSarms.cn-shenzhen.aliyuncs.com CScs.aliyuncs.com COScos.aliyuncs.com Onsons.aliyuncs.com @@ -859,7 +850,7 @@ Stssts.aliyuncs.com Vpcvpc.aliyuncs.com Rdsrds.aliyuncs.com - Mtsmts.cn-hangzhou.aliyuncs.com + Mtsmts.cn-shenzhen.aliyuncs.com Oascn-shenzhen.oas.aliyuncs.com CFcf.aliyuncs.com Acsacs.aliyun-inc.com @@ -908,7 +899,6 @@ Smssms.aliyuncs.com Jaqjaq.aliyuncs.com Dtsdts.aliyuncs.com - Kmskms.cn-hangzhou.aliyuncs.com Locationlocation.aliyuncs.com Essess.aliyuncs.com R-kvstorer-kvstore-cn-hangzhou.aliyuncs.com @@ -937,7 +927,7 @@ CloudAPIapigateway.cn-qingdao.aliyuncs.com Stssts.aliyuncs.com Rdsrds.aliyuncs.com - Mtsmts.cn-hangzhou.aliyuncs.com + Mtsmts.cn-qingdao.aliyuncs.com Location-innerlocation-inner.aliyuncs.com CFcf.aliyuncs.com Acsacs.aliyun-inc.com @@ -1003,6 +993,7 @@ cn-beijing + ARMSarms.cn-beijing.aliyuncs.com CScs.aliyuncs.com COScos.aliyuncs.com Jaqjaq.aliyuncs.com @@ -1046,12 +1037,12 @@ PTSpts.aliyuncs.com M-kvstorem-kvstore.aliyuncs.com Apigatewayapigateway.cn-beijing.aliyuncs.com - CloudAPIapigateway.cn-hangzhou.aliyuncs.com + CloudAPIapigateway.cn-beijing.aliyuncs.com Kmskms.cn-beijing.aliyuncs.com HighDDosyd-highddos-cn-hangzhou.aliyuncs.com CmsSiteMonitorsitemonitor.aliyuncs.com Aceace.cn-hangzhou.aliyuncs.com - Mtsmts.cn-hangzhou.aliyuncs.com + Mtsmts.cn-beijing.aliyuncs.com CFcf.aliyuncs.com Acsacs.aliyun-inc.com Httpdnshttpdns-api.aliyuncs.com @@ -1077,6 +1068,7 @@ Yundunyundun-cn-hangzhou.aliyuncs.com Cdncdn.aliyuncs.com YundunDdosinner-yundun-ddos.cn-hangzhou.aliyuncs.com + vodvod.cn-beijing.aliyuncs.com @@ -1092,7 +1084,6 @@ Smssms.aliyuncs.com Salessales.cn-hangzhou.aliyuncs.com Dtsdts.aliyuncs.com - Kmskms.cn-hangzhou.aliyuncs.com Locationlocation.aliyuncs.com Msgmsg-inner.aliyuncs.com ChargingServicechargingservice.aliyuncs.com @@ -1122,7 +1113,6 @@ PTSpts.aliyuncs.com Qualitycheckqualitycheck.aliyuncs.com Ubsmsubsms.aliyuncs.com - CloudAPIapigateway.cn-hangzhou.aliyuncs.com Rdsrds.aliyuncs.com Mtsmts.cn-hangzhou.aliyuncs.com Location-innerlocation-inner.aliyuncs.com @@ -1180,7 +1170,6 @@ Smssms.aliyuncs.com Jaqjaq.aliyuncs.com Dtsdts.aliyuncs.com - Kmskms.cn-hangzhou.aliyuncs.com Locationlocation.aliyuncs.com Msgmsg-inner.aliyuncs.com ChargingServicechargingservice.aliyuncs.com @@ -1210,7 +1199,6 @@ PTSpts.aliyuncs.com Qualitycheckqualitycheck.aliyuncs.com M-kvstorem-kvstore.aliyuncs.com - CloudAPIapigateway.cn-hangzhou.aliyuncs.com Rdsrds.aliyuncs.com Mtsmts.cn-hangzhou.aliyuncs.com CFcf.aliyuncs.com @@ -1304,11 +1292,11 @@ Bssbss.aliyuncs.com Ubsmsubsms.aliyuncs.com Apigatewayapigateway.ap-southeast-1.aliyuncs.com - CloudAPIapigateway.cn-hangzhou.aliyuncs.com + CloudAPIapigateway.ap-southeast-1.aliyuncs.com Stssts.aliyuncs.com CmsSiteMonitorsitemonitor.aliyuncs.com Aceace.cn-hangzhou.aliyuncs.com - Mtsmts.cn-hangzhou.aliyuncs.com + Mtsmts.ap-southeast-1.aliyuncs.com CFcf.aliyuncs.com Crmcrm-cn-hangzhou.aliyuncs.com Location-innerlocation-inner.aliyuncs.com @@ -1348,4 +1336,14 @@ Slbslb.eu-central-1.aliyuncs.com - \ No newline at end of file + + cn-zhangjiakou + + Rdsrds.cn-zhangjiakou.aliyuncs.com + Ecsecs.cn-zhangjiakou.aliyuncs.com + Vpcvpc.cn-zhangjiakou.aliyuncs.com + Cmsmetrics.cn-hangzhou.aliyuncs.com + Slbslb.cn-zhangjiakou.aliyuncs.com + + + diff --git a/vendor/github.com/denverdino/aliyungo/ecs/forward_entry.go b/vendor/github.com/denverdino/aliyungo/ecs/forward_entry.go new file mode 100644 index 000000000..2a316e18e --- /dev/null +++ b/vendor/github.com/denverdino/aliyungo/ecs/forward_entry.go @@ -0,0 +1,104 @@ +package ecs + +import "github.com/denverdino/aliyungo/common" + +type CreateForwardEntryArgs struct { + RegionId common.Region + ForwardTableId string + ExternalIp string + ExternalPort string + IpProtocol string + InternalIp string + InternalPort string +} + +type CreateForwardEntryResponse struct { + common.Response + ForwardEntryId string +} + +type DescribeForwardTableEntriesArgs struct { + RegionId common.Region + ForwardTableId string + common.Pagination +} + +type ForwardTableEntrySetType struct { + RegionId common.Region + ExternalIp string + ExternalPort string + ForwardEntryId string + ForwardTableId string + InternalIp string + InternalPort string + IpProtocol string + Status string +} + +type DescribeForwardTableEntriesResponse struct { + common.Response + common.PaginationResult + ForwardTableEntries struct { + ForwardTableEntry []ForwardTableEntrySetType + } +} + +type ModifyForwardEntryArgs struct { + RegionId common.Region + ForwardTableId string + ForwardEntryId string + ExternalIp string + IpProtocol string + ExternalPort string + InternalIp string + InternalPort string +} + +type ModifyForwardEntryResponse struct { + common.Response +} + +type DeleteForwardEntryArgs struct { + RegionId common.Region + ForwardTableId string + ForwardEntryId string +} + +type DeleteForwardEntryResponse struct { + common.Response +} + +func (client *Client) CreateForwardEntry(args *CreateForwardEntryArgs) (resp *CreateForwardEntryResponse, err error) { + response := CreateForwardEntryResponse{} + err = client.Invoke("CreateForwardEntry", args, &response) + if err != nil { + return nil, err + } + return &response, err +} + +func (client *Client) DescribeForwardTableEntries(args *DescribeForwardTableEntriesArgs) (forwardTableEntries []ForwardTableEntrySetType, + pagination *common.PaginationResult, err error) { + + args.Validate() + response := DescribeForwardTableEntriesResponse{} + + err = client.Invoke("DescribeForwardTableEntries", args, &response) + + if err != nil { + return nil, nil, err + } + + return response.ForwardTableEntries.ForwardTableEntry, &response.PaginationResult, nil +} + +func (client *Client) ModifyForwardEntry(args *ModifyForwardEntryArgs) error { + response := ModifyForwardEntryResponse{} + return client.Invoke("ModifyForwardEntry", args, &response) +} + +func (client *Client) DeleteForwardEntry(args *DeleteForwardEntryArgs) error { + response := DeleteForwardEntryResponse{} + err := client.Invoke("DeleteForwardEntry", args, &response) + return err +} diff --git a/vendor/github.com/denverdino/aliyungo/ecs/vpcs.go b/vendor/github.com/denverdino/aliyungo/ecs/vpcs.go index 7a62857cd..80faf21ca 100644 --- a/vendor/github.com/denverdino/aliyungo/ecs/vpcs.go +++ b/vendor/github.com/denverdino/aliyungo/ecs/vpcs.go @@ -79,6 +79,7 @@ type VpcSetType struct { CidrBlock string VRouterId string Description string + IsDefault bool CreationTime util.ISO6801Time } diff --git a/vendor/github.com/denverdino/aliyungo/ecs/vswitches.go b/vendor/github.com/denverdino/aliyungo/ecs/vswitches.go index 8bf10394a..8a879ec80 100644 --- a/vendor/github.com/denverdino/aliyungo/ecs/vswitches.go +++ b/vendor/github.com/denverdino/aliyungo/ecs/vswitches.go @@ -77,6 +77,7 @@ type VSwitchSetType struct { AvailableIpAddressCount int Description string VSwitchName string + IsDefault bool CreationTime util.ISO6801Time } diff --git a/vendor/github.com/denverdino/aliyungo/ess/client.go b/vendor/github.com/denverdino/aliyungo/ess/client.go new file mode 100644 index 000000000..a2d486546 --- /dev/null +++ b/vendor/github.com/denverdino/aliyungo/ess/client.go @@ -0,0 +1,48 @@ +package ess + +import ( + "github.com/denverdino/aliyungo/common" + + "os" +) + +type Client struct { + common.Client +} + +const ( + // ESSDefaultEndpoint is the default API endpoint of ESS services + ESSDefaultEndpoint = "https://ess.aliyuncs.com" + ESSAPIVersion = "2014-08-28" + ESSServiceCode = "ess" +) + +// NewClient creates a new instance of RDS client +func NewClient(accessKeyId, accessKeySecret string) *Client { + endpoint := os.Getenv("ESS_ENDPOINT") + if endpoint == "" { + endpoint = ESSDefaultEndpoint + } + return NewClientWithEndpoint(endpoint, accessKeyId, accessKeySecret) +} + +func NewClientWithEndpoint(endpoint string, accessKeyId, accessKeySecret string) *Client { + client := &Client{} + client.Init(endpoint, ESSAPIVersion, accessKeyId, accessKeySecret) + return client +} + +func NewESSClient(accessKeyId, accessKeySecret string, regionID common.Region) *Client { + endpoint := os.Getenv("ESS_ENDPOINT") + if endpoint == "" { + endpoint = ESSDefaultEndpoint + } + + return NewClientWithRegion(endpoint, accessKeyId, accessKeySecret, regionID) +} + +func NewClientWithRegion(endpoint string, accessKeyId, accessKeySecret string, regionID common.Region) *Client { + client := &Client{} + client.NewInit(endpoint, ESSAPIVersion, accessKeyId, accessKeySecret, ESSServiceCode, regionID) + return client +} diff --git a/vendor/github.com/denverdino/aliyungo/ess/configuration.go b/vendor/github.com/denverdino/aliyungo/ess/configuration.go new file mode 100644 index 000000000..7fdcd187c --- /dev/null +++ b/vendor/github.com/denverdino/aliyungo/ess/configuration.go @@ -0,0 +1,127 @@ +package ess + +import ( + "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ecs" +) + +type CreateScalingConfigurationArgs struct { + ScalingGroupId string + ImageId string + InstanceType string + IoOptimized ecs.IoOptimized + SecurityGroupId string + ScalingConfigurationName string + InternetChargeType common.InternetChargeType + InternetMaxBandwidthIn int + InternetMaxBandwidthOut int + SystemDisk_Category common.UnderlineString + SystemDisk_Size common.UnderlineString + DataDisk []DataDiskType +} + +type DataDiskType struct { + Category string + SnapshotId string + Device string + Size int +} + +type CreateScalingConfigurationResponse struct { + ScalingConfigurationId string + common.Response +} + +// CreateScalingConfiguration create scaling configuration +// +// You can read doc at https://help.aliyun.com/document_detail/25944.html?spm=5176.doc25942.6.625.KcE5ir +func (client *Client) CreateScalingConfiguration(args *CreateScalingConfigurationArgs) (resp *CreateScalingConfigurationResponse, err error) { + response := CreateScalingConfigurationResponse{} + err = client.InvokeByFlattenMethod("CreateScalingConfiguration", args, &response) + + if err != nil { + return nil, err + } + return &response, nil +} + +type DescribeScalingConfigurationsArgs struct { + RegionId common.Region + ScalingGroupId string + ScalingConfigurationId common.FlattenArray + ScalingConfigurationName common.FlattenArray + common.Pagination +} + +type DescribeScalingConfigurationsResponse struct { + common.Response + common.PaginationResult + ScalingConfigurations struct { + ScalingConfiguration []ScalingConfigurationItemType + } +} + +type ScalingConfigurationItemType struct { + ScalingConfigurationId string + ScalingConfigurationName string + ScalingGroupId string + ImageId string + InstanceType string + IoOptimized string + SecurityGroupId string + InternetChargeType string + LifecycleState LifecycleState + CreationTime string + InternetMaxBandwidthIn int + InternetMaxBandwidthOut int + SystemDiskCategory string + DataDisks struct { + DataDisk []DataDiskItemType + } +} + +type DataDiskItemType struct { + Size int + Category string + SnapshotId string + Device string +} + +// DescribeScalingConfigurations describes scaling configuration +// +// You can read doc at https://help.aliyun.com/document_detail/25945.html?spm=5176.doc25944.6.626.knG0zz +func (client *Client) DescribeScalingConfigurations(args *DescribeScalingConfigurationsArgs) (configs []ScalingConfigurationItemType, pagination *common.PaginationResult, err error) { + args.Validate() + response := DescribeScalingConfigurationsResponse{} + + err = client.InvokeByFlattenMethod("DescribeScalingConfigurations", args, &response) + + if err == nil { + return response.ScalingConfigurations.ScalingConfiguration, &response.PaginationResult, nil + } + + return nil, nil, err +} + +type DeleteScalingConfigurationArgs struct { + ScalingConfigurationId string + ScalingGroupId string + ImageId string +} + +type DeleteScalingConfigurationResponse struct { + common.Response +} + +// DeleteScalingConfiguration delete scaling configuration +// +// You can read doc at https://help.aliyun.com/document_detail/25946.html?spm=5176.doc25944.6.627.MjkuuL +func (client *Client) DeleteScalingConfiguration(args *DeleteScalingConfigurationArgs) (resp *DeleteScalingConfigurationResponse, err error) { + response := DeleteScalingConfigurationResponse{} + err = client.InvokeByFlattenMethod("DeleteScalingConfiguration", args, &response) + + if err != nil { + return nil, err + } + return &response, nil +} diff --git a/vendor/github.com/denverdino/aliyungo/ess/group.go b/vendor/github.com/denverdino/aliyungo/ess/group.go new file mode 100644 index 000000000..c24e074fd --- /dev/null +++ b/vendor/github.com/denverdino/aliyungo/ess/group.go @@ -0,0 +1,242 @@ +package ess + +import "github.com/denverdino/aliyungo/common" + +type LifecycleState string + +const ( + Active = LifecycleState("Active") + Inacitve = LifecycleState("Inacitve") + Deleting = LifecycleState("Deleting") + InService = LifecycleState("InService") + Pending = LifecycleState("Pending") + Removing = LifecycleState("Removing") +) + +type CreateScalingGroupArgs struct { + RegionId common.Region + ScalingGroupName string + LoadBalancerId string + VpcId string + VSwitchId string + MaxSize int + MinSize int + DefaultCooldown int + RemovalPolicy common.FlattenArray + DBInstanceId common.FlattenArray +} + +type CreateScalingGroupResponse struct { + common.Response + ScalingGroupId string +} + +// CreateScalingGroup create scaling group +// +// You can read doc at https://help.aliyun.com/document_detail/25936.html?spm=5176.doc25940.6.617.vm6LXF +func (client *Client) CreateScalingGroup(args *CreateScalingGroupArgs) (resp *CreateScalingGroupResponse, err error) { + response := CreateScalingGroupResponse{} + err = client.InvokeByFlattenMethod("CreateScalingGroup", args, &response) + + if err != nil { + return nil, err + } + return &response, nil +} + +type ModifyScalingGroupArgs struct { + ScalingGroupId string + ScalingGroupName string + ActiveScalingConfigurationId string + MinSize int + MaxSize int + DefaultCooldown int + RemovalPolicy common.FlattenArray +} + +type ModifyScalingGroupResponse struct { + common.Response +} + +// ModifyScalingGroup modify scaling group +// +// You can read doc at https://help.aliyun.com/document_detail/25937.html?spm=5176.doc25936.6.618.iwDcXT +func (client *Client) ModifyScalingGroup(args *ModifyScalingGroupArgs) (resp *ModifyScalingGroupResponse, err error) { + response := ModifyScalingGroupResponse{} + err = client.InvokeByFlattenMethod("ModifyScalingGroup", args, &response) + + if err != nil { + return nil, err + } + return &response, nil +} + +type DescribeScalingGroupsArgs struct { + RegionId common.Region + ScalingGroupId common.FlattenArray + ScalingGroupName common.FlattenArray + common.Pagination +} + +type DescribeInstancesResponse struct { + common.Response + common.PaginationResult + ScalingGroups struct { + ScalingGroup []ScalingGroupItemType + } +} + +type ScalingGroupItemType struct { + ScalingGroupId string + ScalingGroupName string + ActiveScalingConfigurationId string + RegionId string + LoadBalancerId string + VSwitchId string + CreationTime string + LifecycleState LifecycleState + MinSize int + MaxSize int + DefaultCooldown int + TotalCapacity int + ActiveCapacity int + PendingCapacity int + RemovingCapacity int + RemovalPolicies RemovalPolicySetType + DBInstanceIds DBInstanceIdSetType +} + +type RemovalPolicySetType struct { + RemovalPolicy []string +} + +type DBInstanceIdSetType struct { + DBInstanceId []string +} + +// DescribeScalingGroups describes scaling groups +// +// You can read doc at https://help.aliyun.com/document_detail/25938.html?spm=5176.doc25937.6.619.sUUOT7 +func (client *Client) DescribeScalingGroups(args *DescribeScalingGroupsArgs) (groups []ScalingGroupItemType, pagination *common.PaginationResult, err error) { + args.Validate() + response := DescribeInstancesResponse{} + + err = client.InvokeByFlattenMethod("DescribeScalingGroups", args, &response) + + if err == nil { + return response.ScalingGroups.ScalingGroup, &response.PaginationResult, nil + } + + return nil, nil, err +} + +type DescribeScalingInstancesArgs struct { + RegionId common.Region + ScalingGroupId string + ScalingConfigurationId string + HealthStatus string + CreationType string + LifecycleState LifecycleState + InstanceId common.FlattenArray + common.Pagination +} + +type DescribeScalingInstancesResponse struct { + common.Response + common.PaginationResult + ScalingInstances struct { + ScalingInstance []ScalingInstanceItemType + } +} + +type ScalingInstanceItemType struct { + InstanceId string + ScalingGroupId string + ScalingConfigurationId string + HealthStatus string + CreationTime string + CreationType string + LifecycleState LifecycleState +} + +// DescribeScalingInstances describes scaling instances +// +// You can read doc at https://help.aliyun.com/document_detail/25942.html?spm=5176.doc25941.6.623.2xA0Uj +func (client *Client) DescribeScalingInstances(args *DescribeScalingInstancesArgs) (instances []ScalingInstanceItemType, pagination *common.PaginationResult, err error) { + args.Validate() + response := DescribeScalingInstancesResponse{} + + err = client.InvokeByFlattenMethod("DescribeScalingInstances", args, &response) + + if err == nil { + return response.ScalingInstances.ScalingInstance, &response.PaginationResult, nil + } + + return nil, nil, err +} + +type EnableScalingGroupArgs struct { + ScalingGroupId string + ActiveScalingConfigurationId string + InstanceId common.FlattenArray +} + +type EnableScalingGroupResponse struct { + common.Response +} + +// EnableScalingGroup enable scaling group +// +// You can read doc at https://help.aliyun.com/document_detail/25939.html?spm=5176.doc25938.6.620.JiJhkx +func (client *Client) EnableScalingGroup(args *EnableScalingGroupArgs) (resp *EnableScalingGroupResponse, err error) { + response := EnableScalingGroupResponse{} + err = client.InvokeByFlattenMethod("EnableScalingGroup", args, &response) + + if err != nil { + return nil, err + } + return &response, nil +} + +type DisableScalingGroupArgs struct { + ScalingGroupId string +} + +type DisableScalingGroupResponse struct { + common.Response +} + +// DisableScalingGroup disable scaling group +// +// You can read doc at https://help.aliyun.com/document_detail/25940.html?spm=5176.doc25939.6.621.M8GuuY +func (client *Client) DisableScalingGroup(args *DisableScalingGroupArgs) (resp *DisableScalingGroupResponse, err error) { + response := DisableScalingGroupResponse{} + err = client.InvokeByFlattenMethod("DisableScalingGroup", args, &response) + + if err != nil { + return nil, err + } + return &response, nil +} + +type DeleteScalingGroupArgs struct { + ScalingGroupId string + ForceDelete bool +} + +type DeleteScalingGroupResponse struct { + common.Response +} + +// DeleteScalingGroup delete scaling group +// +// You can read doc at https://help.aliyun.com/document_detail/25941.html?spm=5176.doc25940.6.622.mRBCuw +func (client *Client) DeleteScalingGroup(args *DeleteScalingGroupArgs) (resp *DeleteScalingGroupResponse, err error) { + response := DeleteScalingGroupResponse{} + err = client.InvokeByFlattenMethod("DeleteScalingGroup", args, &response) + + if err != nil { + return nil, err + } + return &response, nil +} diff --git a/vendor/github.com/denverdino/aliyungo/ess/rule.go b/vendor/github.com/denverdino/aliyungo/ess/rule.go new file mode 100644 index 000000000..b6ce29002 --- /dev/null +++ b/vendor/github.com/denverdino/aliyungo/ess/rule.go @@ -0,0 +1,130 @@ +package ess + +import "github.com/denverdino/aliyungo/common" + +type AdjustmentType string + +const ( + QuantityChangeInCapacity = AdjustmentType("QuantityChangeInCapacity") + PercentChangeInCapacity = AdjustmentType("PercentChangeInCapacity") + TotalCapacity = AdjustmentType("TotalCapacity") +) + +type CreateScalingRuleArgs struct { + RegionId common.Region + ScalingGroupId string + AdjustmentType AdjustmentType + AdjustmentValue int + Cooldown int + ScalingRuleName string +} + +type CreateScalingRuleResponse struct { + common.Response + ScalingRuleId string + ScalingRuleAri string +} + +// CreateScalingRule create scaling rule +// +// You can read doc at https://help.aliyun.com/document_detail/25948.html?spm=5176.doc25944.6.629.FLkNnj +func (client *Client) CreateScalingRule(args *CreateScalingRuleArgs) (resp *CreateScalingRuleResponse, err error) { + response := CreateScalingRuleResponse{} + err = client.Invoke("CreateScalingRule", args, &response) + + if err != nil { + return nil, err + } + return &response, nil +} + +type ModifyScalingRuleArgs struct { + RegionId common.Region + ScalingRuleId string + AdjustmentType AdjustmentType + AdjustmentValue int + Cooldown int + ScalingRuleName string +} + +type ModifyScalingRuleResponse struct { + common.Response +} + +// ModifyScalingRule modify scaling rule +// +// You can read doc at https://help.aliyun.com/document_detail/25949.html?spm=5176.doc25948.6.630.HGN1va +func (client *Client) ModifyScalingRule(args *ModifyScalingRuleArgs) (resp *ModifyScalingRuleResponse, err error) { + response := ModifyScalingRuleResponse{} + err = client.Invoke("ModifyScalingRule", args, &response) + + if err != nil { + return nil, err + } + return &response, nil +} + +type DescribeScalingRulesArgs struct { + common.Pagination + RegionId common.Region + ScalingGroupId string + ScalingRuleId common.FlattenArray + ScalingRuleName common.FlattenArray + ScalingRuleAri common.FlattenArray +} + +type DescribeScalingRulesResponse struct { + common.Response + common.PaginationResult + ScalingRules struct { + ScalingRule []ScalingRuleItemType + } +} + +type ScalingRuleItemType struct { + ScalingRuleId string + ScalingGroupId string + ScalingRuleName string + AdjustmentType string + ScalingRuleAri string + Cooldown int + AdjustmentValue int +} + +// DescribeScalingRules describes scaling rules +// +// You can read doc at https://help.aliyun.com/document_detail/25950.html?spm=5176.doc25949.6.631.RwPguo +func (client *Client) DescribeScalingRules(args *DescribeScalingRulesArgs) (configs []ScalingRuleItemType, pagination *common.PaginationResult, err error) { + args.Validate() + response := DescribeScalingRulesResponse{} + + err = client.InvokeByFlattenMethod("DescribeScalingRules", args, &response) + + if err == nil { + return response.ScalingRules.ScalingRule, &response.PaginationResult, nil + } + + return nil, nil, err +} + +type DeleteScalingRuleArgs struct { + RegionId common.Region + ScalingRuleId string +} + +type DeleteScalingRuleResponse struct { + common.Response +} + +// DeleteScalingRule delete scaling rule +// +// You can read doc at https://help.aliyun.com/document_detail/25951.html?spm=5176.doc25950.6.632.HbPLMZ +func (client *Client) DeleteScalingRule(args *DeleteScalingRuleArgs) (resp *DeleteScalingRuleResponse, err error) { + response := DeleteScalingRuleResponse{} + err = client.InvokeByFlattenMethod("DeleteScalingRule", args, &response) + + if err != nil { + return nil, err + } + return &response, nil +} diff --git a/vendor/github.com/denverdino/aliyungo/ess/schedule.go b/vendor/github.com/denverdino/aliyungo/ess/schedule.go new file mode 100644 index 000000000..9da5a86e0 --- /dev/null +++ b/vendor/github.com/denverdino/aliyungo/ess/schedule.go @@ -0,0 +1,140 @@ +package ess + +import "github.com/denverdino/aliyungo/common" + +type RecurrenceType string + +const ( + Daily = RecurrenceType("Daily") + Weekly = RecurrenceType("Weekly") + Monthly = RecurrenceType("Monthly") +) + +type CreateScheduledTaskArgs struct { + RegionId common.Region + ScheduledAction string + LaunchTime string + ScheduledTaskName string + Description string + LaunchExpirationTime int + RecurrenceType RecurrenceType + RecurrenceValue string + RecurrenceEndTime string + TaskEnabled bool +} + +type CreateScheduledTaskResponse struct { + common.Response + ScheduledTaskId string +} + +// CreateScheduledTask create schedule task +// +// You can read doc at https://help.aliyun.com/document_detail/25957.html?spm=5176.doc25950.6.638.FfQ0BR +func (client *Client) CreateScheduledTask(args *CreateScheduledTaskArgs) (resp *CreateScheduledTaskResponse, err error) { + response := CreateScheduledTaskResponse{} + err = client.Invoke("CreateScheduledTask", args, &response) + + if err != nil { + return nil, err + } + return &response, nil +} + +type ModifyScheduledTaskArgs struct { + RegionId common.Region + ScheduledTaskId string + ScheduledAction string + LaunchTime string + ScheduledTaskName string + Description string + LaunchExpirationTime int + RecurrenceType RecurrenceType + RecurrenceValue string + RecurrenceEndTime string + TaskEnabled bool +} + +type ModifyScheduledTaskResponse struct { + common.Response +} + +// ModifyScheduledTask modify schedule task +// +// You can read doc at https://help.aliyun.com/document_detail/25958.html?spm=5176.doc25957.6.639.rgxQ1c +func (client *Client) ModifyScheduledTask(args *ModifyScheduledTaskArgs) (resp *ModifyScheduledTaskResponse, err error) { + response := ModifyScheduledTaskResponse{} + err = client.Invoke("ModifyScheduledTask", args, &response) + + if err != nil { + return nil, err + } + return &response, nil +} + +type DescribeScheduledTasksArgs struct { + RegionId common.Region + ScheduledTaskId common.FlattenArray + ScheduledTaskName common.FlattenArray + ScheduledAction common.FlattenArray + common.Pagination +} + +type DescribeScheduledTasksResponse struct { + common.Response + common.PaginationResult + ScheduledTasks struct { + ScheduledTask []ScheduledTaskItemType + } +} + +type ScheduledTaskItemType struct { + ScheduledTaskId string + ScheduledTaskName string + Description string + ScheduledAction string + LaunchTime string + RecurrenceType string + RecurrenceValue string + RecurrenceEndTime string + LaunchExpirationTime int + TaskEnabled bool +} + +// DescribeScheduledTasks describes scaling tasks +// +// You can read doc at https://help.aliyun.com/document_detail/25959.html?spm=5176.doc25958.6.640.cLccdR +func (client *Client) DescribeScheduledTasks(args *DescribeScheduledTasksArgs) (tasks []ScheduledTaskItemType, pagination *common.PaginationResult, err error) { + args.Validate() + response := DescribeScheduledTasksResponse{} + + err = client.InvokeByFlattenMethod("DescribeScheduledTasks", args, &response) + + if err == nil { + return response.ScheduledTasks.ScheduledTask, &response.PaginationResult, nil + } + + return nil, nil, err +} + +type DeleteScheduledTaskArgs struct { + RegionId common.Region + ScheduledTaskId string +} + +type DeleteScheduledTaskResponse struct { + common.Response +} + +// DeleteScheduledTask delete schedule task +// +// You can read doc at https://help.aliyun.com/document_detail/25960.html?spm=5176.doc25959.6.641.aGdNuW +func (client *Client) DeleteScheduledTask(args *DeleteScheduledTaskArgs) (resp *DeleteScheduledTaskResponse, err error) { + response := DeleteScheduledTaskResponse{} + err = client.Invoke("DeleteScheduledTask", args, &response) + + if err != nil { + return nil, err + } + return &response, nil +} diff --git a/vendor/github.com/denverdino/aliyungo/util/encoding.go b/vendor/github.com/denverdino/aliyungo/util/encoding.go index e545e069d..8cb588288 100644 --- a/vendor/github.com/denverdino/aliyungo/util/encoding.go +++ b/vendor/github.com/denverdino/aliyungo/util/encoding.go @@ -7,9 +7,26 @@ import ( "net/url" "reflect" "strconv" + "strings" "time" ) +// change instance=["a", "b"] +// to instance.1="a" instance.2="b" +func FlattenFn(fieldName string, field reflect.Value, values *url.Values) { + l := field.Len() + if l > 0 { + for i := 0; i < l; i++ { + str := field.Index(i).String() + values.Set(fieldName+"."+strconv.Itoa(i+1), str) + } + } +} + +func Underline2Dot(name string) string { + return strings.Replace(name, "_", ".", -1) +} + //ConvertToQueryValues converts the struct to url.Values func ConvertToQueryValues(ifc interface{}) url.Values { values := url.Values{} @@ -22,6 +39,10 @@ func SetQueryValues(ifc interface{}, values *url.Values) { setQueryValues(ifc, values, "") } +func SetQueryValueByFlattenMethod(ifc interface{}, values *url.Values) { + setQueryValuesByFlattenMethod(ifc, values, "") +} + func setQueryValues(i interface{}, values *url.Values, prefix string) { // add to support url.Values mapValues, ok := i.(url.Values) @@ -150,3 +171,144 @@ func setQueryValues(i interface{}, values *url.Values, prefix string) { } } } + +func setQueryValuesByFlattenMethod(i interface{}, values *url.Values, prefix string) { + // add to support url.Values + mapValues, ok := i.(url.Values) + if ok { + for k, _ := range mapValues { + values.Set(k, mapValues.Get(k)) + } + return + } + + elem := reflect.ValueOf(i) + if elem.Kind() == reflect.Ptr { + elem = elem.Elem() + } + elemType := elem.Type() + for i := 0; i < elem.NumField(); i++ { + + fieldName := elemType.Field(i).Name + anonymous := elemType.Field(i).Anonymous + field := elem.Field(i) + + // TODO Use Tag for validation + // tag := typ.Field(i).Tag.Get("tagname") + kind := field.Kind() + + if (kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map || kind == reflect.Chan) && field.IsNil() { + continue + } + if kind == reflect.Ptr { + field = field.Elem() + kind = field.Kind() + } + + var value string + //switch field.Interface().(type) { + switch kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i := field.Int() + if i != 0 { + value = strconv.FormatInt(i, 10) + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + i := field.Uint() + if i != 0 { + value = strconv.FormatUint(i, 10) + } + case reflect.Float32: + value = strconv.FormatFloat(field.Float(), 'f', 4, 32) + case reflect.Float64: + value = strconv.FormatFloat(field.Float(), 'f', 4, 64) + case reflect.Bool: + value = strconv.FormatBool(field.Bool()) + case reflect.String: + value = field.String() + case reflect.Map: + ifc := field.Interface() + m := ifc.(map[string]string) + if m != nil { + j := 0 + for k, v := range m { + j++ + keyName := fmt.Sprintf("%s.%d.Key", fieldName, j) + values.Set(keyName, k) + valueName := fmt.Sprintf("%s.%d.Value", fieldName, j) + values.Set(valueName, v) + } + } + case reflect.Slice: + if field.Type().Name() == "FlattenArray" { + FlattenFn(fieldName, field, values) + } else { + switch field.Type().Elem().Kind() { + case reflect.Uint8: + value = string(field.Bytes()) + case reflect.String: + l := field.Len() + if l > 0 { + strArray := make([]string, l) + for i := 0; i < l; i++ { + strArray[i] = field.Index(i).String() + } + bytes, err := json.Marshal(strArray) + if err == nil { + value = string(bytes) + } else { + log.Printf("Failed to convert JSON: %v", err) + } + } + default: + l := field.Len() + for j := 0; j < l; j++ { + prefixName := fmt.Sprintf("%s.%d.", fieldName, (j + 1)) + ifc := field.Index(j).Interface() + //log.Printf("%s : %v", prefixName, ifc) + if ifc != nil { + setQueryValuesByFlattenMethod(ifc, values, prefixName) + } + } + continue + } + } + + default: + switch field.Interface().(type) { + case ISO6801Time: + t := field.Interface().(ISO6801Time) + value = t.String() + case time.Time: + t := field.Interface().(time.Time) + value = GetISO8601TimeStamp(t) + default: + + ifc := field.Interface() + if ifc != nil { + if anonymous { + SetQueryValues(ifc, values) + } else { + prefixName := fieldName + "." + setQueryValuesByFlattenMethod(ifc, values, prefixName) + } + continue + } + } + } + if value != "" { + name := elemType.Field(i).Tag.Get("ArgName") + if name == "" { + name = fieldName + } + if prefix != "" { + name = prefix + name + } + // NOTE: here we will change name to underline style when the type is UnderlineString + if field.Type().Name() == "UnderlineString" { + name = Underline2Dot(name) + } + values.Set(name, value) + } + } +} diff --git a/vendor/vendor.json b/vendor/vendor.json index f15250981..205e2eb02 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1300,34 +1300,40 @@ "revisionTime": "2016-10-29T20:57:26Z" }, { - "checksumSHA1": "SdiAYZOqWQ60ifRUHLwLiDMKMYA=", + "checksumSHA1": "4YIveqfMA1MH8oX8YMG7rDSl+ms=", "path": "github.com/denverdino/aliyungo/common", - "revision": "c4c75afbf7ea86e66672c1b6ed981385b4ad5ec2", - "revisionTime": "2017-03-21T07:55:32Z" + "revision": "afcc6903e3f10217da17e315558b3f829718ee04", + "revisionTime": "2017-04-13T09:54:00Z" }, { - "checksumSHA1": "UVYu5rvfoXgJnIpUyGcaovMvpms=", + "checksumSHA1": "WkWWoA5aRYkE2apOEQdAOfn+9cc=", "path": "github.com/denverdino/aliyungo/ecs", - "revision": "c4c75afbf7ea86e66672c1b6ed981385b4ad5ec2", - "revisionTime": "2017-03-21T07:55:32Z" + "revision": "afcc6903e3f10217da17e315558b3f829718ee04", + "revisionTime": "2017-04-13T09:54:00Z" + }, + { + "checksumSHA1": "BgIs8qwCMRM8xL6oLeo2Ki1QwBc=", + "path": "github.com/denverdino/aliyungo/ess", + "revision": "afcc6903e3f10217da17e315558b3f829718ee04", + "revisionTime": "2017-04-13T09:54:00Z" }, { "checksumSHA1": "riQMe2AR7qkLRkQ/MSr8gQp3zL4=", "path": "github.com/denverdino/aliyungo/rds", - "revision": "c4c75afbf7ea86e66672c1b6ed981385b4ad5ec2", - "revisionTime": "2017-03-21T07:55:32Z" + "revision": "afcc6903e3f10217da17e315558b3f829718ee04", + "revisionTime": "2017-04-13T09:54:00Z" }, { "checksumSHA1": "2g6VZONB51rul5YuSBvngH6u4A0=", "path": "github.com/denverdino/aliyungo/slb", - "revision": "c4c75afbf7ea86e66672c1b6ed981385b4ad5ec2", - "revisionTime": "2017-03-21T07:55:32Z" + "revision": "afcc6903e3f10217da17e315558b3f829718ee04", + "revisionTime": "2017-04-13T09:54:00Z" }, { - "checksumSHA1": "Lp0KtT7ycgq31ox3Uzhpxyw0U+Y=", + "checksumSHA1": "piZlmhWPLGxYkXLysTrjcXllO4c=", "path": "github.com/denverdino/aliyungo/util", - "revision": "c4c75afbf7ea86e66672c1b6ed981385b4ad5ec2", - "revisionTime": "2017-03-21T07:55:32Z" + "revision": "afcc6903e3f10217da17e315558b3f829718ee04", + "revisionTime": "2017-04-13T09:54:00Z" }, { "checksumSHA1": "yDQQpeUxwqB3C+4opweg6znWJQk=", diff --git a/website/source/docs/providers/alicloud/r/db_instance.html.markdown b/website/source/docs/providers/alicloud/r/db_instance.html.markdown index ee3a78071..7580f61e6 100644 --- a/website/source/docs/providers/alicloud/r/db_instance.html.markdown +++ b/website/source/docs/providers/alicloud/r/db_instance.html.markdown @@ -6,7 +6,7 @@ description: |- Provides an RDS instance resource. --- -# alicloud_db_instance +# 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 @@ -14,16 +14,14 @@ databases. ## Example Usage -```hcl +``` 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" + 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" } ``` @@ -32,13 +30,13 @@ resource "alicloud_db_instance" "default" { The following arguments are supported: * `engine` - (Required) Database type. Value options: MySQL, SQLServer, PostgreSQL, and PPAS. -* `engine_version` - (Required) Database version. Value options: +* `engine_version` - (Required) Database version. Value options: - 5.5/5.6/5.7 for MySQL - 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_storage` - (Required) User-defined 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; @@ -65,7 +63,7 @@ The following arguments are supported: 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. +* `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 @@ -78,7 +76,7 @@ The database mapping supports the following: + 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://. +* `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. @@ -105,3 +103,4 @@ The following attributes are exported: * `backup_retention_period` - Retention days of the backup. * `security_ips` - Security ips of instance whitelist. * `connections` - Views all the connection information of a specified instance. + diff --git a/website/source/docs/providers/alicloud/r/disk.html.markdown b/website/source/docs/providers/alicloud/r/disk.html.markdown index 1b4098a31..82814b732 100644 --- a/website/source/docs/providers/alicloud/r/disk.html.markdown +++ b/website/source/docs/providers/alicloud/r/disk.html.markdown @@ -1,12 +1,12 @@ --- layout: "alicloud" page_title: "Alicloud: alicloud_disk" -sidebar_current: "docs-alicloud-resource-disk." +sidebar_current: "docs-alicloud-resource-disk" description: |- Provides a ECS Disk resource. --- -# alicloud_disk +# alicloud\_disk Provides a ECS disk resource. @@ -14,8 +14,10 @@ Provides a ECS disk resource. ## Example Usage -```hcl +``` +# Create a new ECS disk. resource "alicloud_disk" "ecs_disk" { + # cn-beijing availability_zone = "cn-beijing-b" name = "New-disk" description = "Hello ecs disk." @@ -32,7 +34,7 @@ resource "alicloud_disk" "ecs_disk" { The following arguments are supported: * `availability_zone` - (Required, Forces new resource) The Zone to create the disk in. -* `name` - (Optional) Name of the ECS disk. This name can have a string of 2 to 128 characters, must contain only alphanumeric characters or hyphens, such as "-",".","\_", and must not begin or end with a hyphen, and must not begin with http:// or https://. Default value is null. +* `name` - (Optional) Name of the ECS disk. This name can have a string of 2 to 128 characters, must contain only alphanumeric characters or hyphens, such as "-",".","_", and must not begin or end with a hyphen, and must not begin with http:// or https://. Default value is null. * `description` - (Optional) Description of the disk. This description can have a string of 2 to 256 characters, It cannot begin with http:// or https://. Default value is null. * `category` - (Optional, Forces new resource) Category of the disk. Valid values are `cloud`, `cloud_efficiency` and `cloud_ssd`. Default is `cloud`. * `size` - (Required) The size of the disk in GiBs, and its value depends on `Category`. `cloud` disk value range: 5GB ~ 2000GB and other category disk value range: 20 ~ 32768. @@ -51,4 +53,4 @@ The following attributes are exported: * `category` - The disk category. * `size` - The disk size. * `snapshot_id` - The disk snapshot ID. -* `tags` - The disk tags. +* `tags` - The disk tags. \ No newline at end of file diff --git a/website/source/docs/providers/alicloud/r/disk_attachment.html.markdown b/website/source/docs/providers/alicloud/r/disk_attachment.html.markdown index 4e500650f..d39e85a4c 100644 --- a/website/source/docs/providers/alicloud/r/disk_attachment.html.markdown +++ b/website/source/docs/providers/alicloud/r/disk_attachment.html.markdown @@ -6,7 +6,7 @@ description: |- Provides a ECS Disk Attachment resource. --- -# alicloud_disk_attachment +# alicloud\_disk\_attachment Provides an Alicloud ECS Disk Attachment as a resource, to attach and detach disks from ECS Instances. @@ -14,7 +14,9 @@ Provides an Alicloud ECS Disk Attachment as a resource, to attach and detach dis Basic usage -```hcl +``` +# Create a new ECS disk-attachment and use it attach one disk to a new instance. + resource "alicloud_security_group" "ecs_sg" { name = "terraform-test-group" description = "New security group" @@ -63,4 +65,4 @@ The following attributes are exported: * `instance_id` - ID of the Instance. * `disk_id` - ID of the Disk. -* `device_name` - The device name exposed to the instance. +* `device_name` - The device name exposed to the instance. \ No newline at end of file diff --git a/website/source/docs/providers/alicloud/r/eip.html.markdown b/website/source/docs/providers/alicloud/r/eip.html.markdown index e602d50c1..ddb1b7689 100644 --- a/website/source/docs/providers/alicloud/r/eip.html.markdown +++ b/website/source/docs/providers/alicloud/r/eip.html.markdown @@ -1,18 +1,18 @@ --- layout: "alicloud" page_title: "Alicloud: alicloud_eip" -sidebar_current: "docs-alicloud-resource-eip." +sidebar_current: "docs-alicloud-resource-eip" description: |- Provides a ECS EIP resource. --- -# alicloud_eip +# alicloud\_eip Provides a ECS EIP resource. ## Example Usage -```hcl +``` # Create a new EIP. resource "alicloud_eip" "example" { bandwidth = "10" diff --git a/website/source/docs/providers/alicloud/r/eip_association.html.markdown b/website/source/docs/providers/alicloud/r/eip_association.html.markdown index 2e3f996be..6c0d7059a 100644 --- a/website/source/docs/providers/alicloud/r/eip_association.html.markdown +++ b/website/source/docs/providers/alicloud/r/eip_association.html.markdown @@ -6,7 +6,7 @@ description: |- Provides a ECS EIP Association resource. --- -# alicloud_eip_association +# alicloud\_eip\_association Provides an Alicloud EIP Association resource, to associate and disassociate Elastic IPs from ECS Instances. @@ -16,7 +16,9 @@ Provides an Alicloud EIP Association resource, to associate and disassociate Ela ## Example Usage -```hcl +``` +# Create a new EIP association and use it to associate a EIP form a instance. + resource "alicloud_vpc" "vpc" { cidr_block = "10.1.0.0/21" } @@ -71,4 +73,4 @@ The following arguments are supported: The following attributes are exported: * `allocation_id` - As above. -* `instance_id` - As above. +* `instance_id` - As above. \ No newline at end of file diff --git a/website/source/docs/providers/alicloud/r/ess_scaling_configuration.html.markdown b/website/source/docs/providers/alicloud/r/ess_scaling_configuration.html.markdown new file mode 100644 index 000000000..003b7c988 --- /dev/null +++ b/website/source/docs/providers/alicloud/r/ess_scaling_configuration.html.markdown @@ -0,0 +1,84 @@ +--- +layout: "alicloud" +page_title: "Alicloud: alicloud_ess_scaling_configuration" +sidebar_current: "docs-alicloud-resource-ess-scaling-configuration" +description: |- + Provides a ESS scaling configuration resource. +--- + +# alicloud\_ess\_scaling\_configuration + +Provides a ESS scaling configuration resource. + +## Example Usage + +``` +resource "alicloud_security_group" "classic" { + # Other parameters... +} +resource "alicloud_ess_scaling_group" "scaling" { + min_size = 1 + max_size = 2 + removal_policies = ["OldestInstance", "NewestInstance"] +} + +resource "alicloud_ess_scaling_configuration" "config" { + scaling_group_id = "${alicloud_ess_scaling_group.scaling.id}" + + image_id = "ubuntu_140405_64_40G_cloudinit_20161115.vhd" + instance_type = "ecs.s2.large" + security_group_id = "${alicloud_security_group.classic.id}" +} + +``` + +## Argument Reference + +The following arguments are supported: + +* `scaling_group_id` - (Required) ID of the scaling group of a scaling configuration. +* `image_id` - (Required) ID of an image file, indicating the image resource selected when an instance is enabled. +* `instance_type` - (Required) Resource type of an ECS instance. +* `io_optimized` - (Required) Valid values are `none`, `optimized`, If `optimized`, the launched ECS instance will be I/O optimized. +* `security_group_id` - (Required) ID of the security group to which a newly created instance belongs. +* `scaling_configuration_name` - (Optional) Name shown for the scheduled task. If this parameter value is not specified, the default value is ScalingConfigurationId. +* `internet_charge_type` - (Optional) Network billing type, Values: PayByBandwidth or PayByTraffic. If this parameter value is not specified, the default value is PayByBandwidth. +* `internet_max_bandwidth_in` - (Optional) Maximum incoming bandwidth from the public network, measured in Mbps (Mega bit per second). The value range is [1,200]. +* `internet_max_bandwidth_out` - (Optional) Maximum outgoing bandwidth from the public network, measured in Mbps (Mega bit per second). The value range for PayByBandwidth is [1,100]. +* `system_disk_category` - (Optional) Category of the system disk. The parameter value options are cloud and ephemeral. +* `data_disk` - (Optional) DataDisk mappings to attach to ecs instance. See [Block datadisk](#block-datadisk) below for details. +* `instance_ids` - (Optional) ID of the ECS instance to be attached to the scaling group after it is enabled. You can input up to 20 IDs. + + +## Block datadisk + +The datadisk mapping supports the following: + +* `size` - (Optional) Size of data disk, in GB. The value ranges from 5 to 2,000 for a cloud disk and from 5 to 1,024 for an ephemeral disk. A maximum of four values can be entered. +* `category` - (Optional) Category of data disk. The parameter value options are cloud and ephemeral. +* `snapshot_id` - (Optional) Snapshot used for creating the data disk. If this parameter is specified, the size parameter is neglected, and the size of the created disk is the size of the snapshot. +* `device` - (Optional) Attaching point of the data disk. If this parameter is empty, the ECS automatically assigns the attaching point when an ECS is created. The parameter value ranges from /dev/xvdb to /dev/xvdz. Restrictions on attaching ECS instances: + - The attached ECS instance and the scaling group must be in the same region. + - The attached ECS instance and the instance with active scaling configurations must be of the same type. + - The attached ECS instance must in the running state. + - The attached ECS instance has not been attached to other scaling groups. + - The attached ECS instance supports Subscription and Pay-As-You-Go payment methods. + - If the VswitchID is specified for a scaling group, you cannot attach Classic ECS instances or ECS instances on other VPCs to the scaling group. + - If the VswitchID is not specified for the scaling group, ECS instances of the VPC type cannot be attached to the scaling group +* `active` - (Optional) If active current scaling configuration in the scaling group. +* `enable` - (Optional) Enables the specified scaling group. + - After the scaling group is successfully enabled (the group is active), the ECS instances specified by the interface are attached to the group. + - If the current number of ECS instances in the scaling group is still smaller than MinSize after the ECS instances specified by the interface are attached, the Auto Scaling service automatically creates ECS instances in Pay-As-You-Go mode to make odds even. For example, a scaling group is created with MinSize = 5. Two existing ECS instances are specified by the InstanceId.N parameter when the scaling group is enabled. Three additional ECS instances are automatically created after the two ECS instances are attached by the Auto Scaling service to the scaling group. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The scaling configuration ID. +* `active` - Wether the current scaling configuration is actived. +* `image_id` - The ecs instance Image id. +* `instance_type` - The ecs instance type. +* `io_optimized` - The ecs instance whether I/O optimized. +* `security_group_id` - ID of the security group to which a newly created instance belongs. +* `scaling_configuration_name` - Name of scaling configuration. +* `internet_charge_type` - Internet charge type of ecs instance. \ No newline at end of file diff --git a/website/source/docs/providers/alicloud/r/ess_scaling_group.html.markdown b/website/source/docs/providers/alicloud/r/ess_scaling_group.html.markdown new file mode 100644 index 000000000..f039c5f19 --- /dev/null +++ b/website/source/docs/providers/alicloud/r/ess_scaling_group.html.markdown @@ -0,0 +1,57 @@ +--- +layout: "alicloud" +page_title: "Alicloud: alicloud_ess_scaling_group" +sidebar_current: "docs-alicloud-resource-ess-scaling-group" +description: |- + Provides a ESS scaling group resource. +--- + +# alicloud\_ess\_scaling\_group + +Provides a ESS scaling group resource. + +## Example Usage + +``` +resource "alicloud_ess_scaling_group" "scaling" { + min_size = 1 + max_size = 2 + removal_policies = ["OldestInstance", "NewestInstance"] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `min_size` - (Required) Minimum number of ECS instances in the scaling group. Value range: [0, 100]. +* `max_size` - (Required) Maximum number of ECS instances in the scaling group. Value range: [0, 100]. +* `scaling_group_name` - (Optional) Name shown for the scaling group, which must contain 2-40 characters (English or Chinese). If this parameter is not specified, the default value is ScalingGroupId. +* `default_cooldown` - (Optional) Default cool-down time (in seconds) of the scaling group. Value range: [0, 86400]. The default value is 300s. +* `vswitch_id` - (Optional) The virtual switch ID which the ecs instance to be create in. +* `removal_policies` - (Optional) RemovalPolicy is used to select the ECS instances you want to remove from the scaling group when multiple candidates for removal exist. Optional values: + - OldestInstance: removes the first ECS instance attached to the scaling group. + - NewestInstance: removes the first ECS instance attached to the scaling group. + - OldestScalingConfiguration: removes the ECS instance with the oldest scaling configuration. + - Default values: OldestScalingConfiguration and OldestInstance. You can enter up to two removal policies. +* `db_instance_ids` - (Optional) If an RDS instance is specified in the scaling group, the scaling group automatically attaches the Intranet IP addresses of its ECS instances to the RDS access whitelist. + - The specified RDS instance must be in running status. + - The specified RDS instance’s whitelist must have room for more IP addresses. +* `loadbalancer_ids` - (Optional) If a Server Load Balancer instance is specified in the scaling group, the scaling group automatically attaches its ECS instances to the Server Load Balancer instance. + - The Server Load Balancer instance must be enabled. + - Health check must be enabled for all listener ports configured for the Server Load Balancer instance; otherwise, creation fails. + - The Server Load Balancer instance attached with VPC-type ECS instances cannot be attached to the scaling group. + - The default weight of an ECS instance attached to the Server Load Balancer instance is 50. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The scaling group ID. +* `min_size` - The minimum number of ECS instances. +* `max_size` - The maximum number of ECS instances. +* `scaling_group_name` - The name of the scaling group. +* `default_cooldown` - The default cool-down of the scaling group. +* `removal_policies` - The removal policy used to select the ECS instance to remove from the scaling group. +* `db_instance_ids` - The db instance id which the ECS instance attached to. +* `loadbalancer_ids` - The slb instance id which the ECS instance attached to. \ No newline at end of file diff --git a/website/source/docs/providers/alicloud/r/ess_scaling_rule.html.markdown b/website/source/docs/providers/alicloud/r/ess_scaling_rule.html.markdown new file mode 100644 index 000000000..ec24b5067 --- /dev/null +++ b/website/source/docs/providers/alicloud/r/ess_scaling_rule.html.markdown @@ -0,0 +1,59 @@ +--- +layout: "alicloud" +page_title: "Alicloud: alicloud_ess_scaling_rule" +sidebar_current: "docs-alicloud-resource-ess-scaling-rule" +description: |- + Provides a ESS scaling rule resource. +--- + +# alicloud\_ess\_scaling\_rule + +Provides a ESS scaling rule resource. + +## Example Usage + +``` +resource "alicloud_ess_scaling_group" "scaling" { + # Other parameters... +} + +resource "alicloud_ess_scaling_configuration" "config" { + # Other parameters... +} + +resource "alicloud_ess_scaling_rule" "rule" { + scaling_group_id = "${alicloud_ess_scaling_group.scaling.id}" + adjustment_type = "TotalCapacity" + adjustment_value = 2 + cooldown = 60 +} +``` + +## Argument Reference + +The following arguments are supported: + +* `scaling_group_id` - (Required) ID of the scaling group of a scaling rule. +* `adjustment_type` - (Required) Adjustment mode of a scaling rule. Optional values: + - QuantityChangeInCapacity: It is used to increase or decrease a specified number of ECS instances. + - PercentChangeInCapacity: It is used to increase or decrease a specified proportion of ECS instances. + - TotalCapacity: It is used to adjust the quantity of ECS instances in the current scaling group to a specified value. +* `adjustment_value` - (Required) Adjusted value of a scaling rule. Value range: + - QuantityChangeInCapacity:(0, 100] U (-100, 0] + - PercentChangeInCapacity:[0, 10000] U [-10000, 0] + - TotalCapacity:[0, 100] +* `scaling_rule_name` - (Optional) Name shown for the scaling rule, which is a string containing 2 to 40 English or Chinese characters. +* `cooldown` - (Optional) Cool-down time of a scaling rule. Value range: [0, 86,400], in seconds. The default value is empty. + + +## Attributes Reference + +The following attributes are exported: + +* `id` - The scaling rule ID. +* `scaling_group_id` - The id of scaling group. +* `ari` - Unique identifier of a scaling rule. +* `adjustment_type` - Adjustment mode of a scaling rule. +* `adjustment_value` - Adjustment value of a scaling rule. +* `scaling_rule_name` - Name of a scaling rule. +* `cooldown` - Cool-down time of a scaling rule. \ No newline at end of file diff --git a/website/source/docs/providers/alicloud/r/ess_schedule.html.markdown b/website/source/docs/providers/alicloud/r/ess_schedule.html.markdown new file mode 100644 index 000000000..abe2a298e --- /dev/null +++ b/website/source/docs/providers/alicloud/r/ess_schedule.html.markdown @@ -0,0 +1,65 @@ +--- +layout: "alicloud" +page_title: "Alicloud: alicloud_ess_schedule" +sidebar_current: "docs-alicloud-resource-ess-schedule" +description: |- + Provides a ESS schedule resource. +--- + +# alicloud\_ess\_schedule + +Provides a ESS schedule resource. + +## Example Usage + +``` +resource "alicloud_ess_scaling_group" "scaling" { + # Other parameters... +} + +resource "alicloud_ess_scaling_configuration" "config" { + # Other parameters... +} + +resource "alicloud_ess_scaling_rule" "rule" { + # Other parameters... +} + +resource "alicloud_ess_schedule" "schedule" { + scheduled_action = "${alicloud_ess_scaling_rule.rule.ari}" + launch_time = "2017-04-29T07:30Z" + scheduled_task_name = "sg-schedule" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `scheduled_action` - (Required) Operations performed when the scheduled task is triggered. Fill in the unique identifier of the scaling rule. +* `launch_time` - (Required) Operations performed when the scheduled task is triggered. Fill in the unique identifier of the scaling rule. +* `scheduled_task_name` - (Optional) Display name of the scheduled task, which must be 2-40 characters (English or Chinese) long. +* `description` - (Optional) Description of the scheduled task, which is 2-200 characters (English or Chinese) long. +* `launch_expiration_time` - (Optional) Time period within which the failed scheduled task is retried. The default value is 600s. Value range: [0, 21600] +* `recurrence_type` - (Optional) Type of the scheduled task to be repeated. RecurrenceType, RecurrenceValue and RecurrenceEndTime must be specified. Optional values: + - Daily: Recurrence interval by day for a scheduled task. + - Weekly: Recurrence interval by week for a scheduled task. + - Monthly: Recurrence interval by month for a scheduled task. +* `recurrence_value` - (Optional) Value of the scheduled task to be repeated. RecurrenceType, RecurrenceValue and RecurrenceEndTime must be specified. + - Daily: Only one value in the range [1,31] can be filled. + - Weekly: Multiple values can be filled. The values of Sunday to Saturday are 0 to 6 in sequence. Multiple values shall be separated by a comma “,”. + - Monthly: In the format of A-B. The value range of A and B is 1 to 31, and the B value must be greater than the A value. +* `recurrence_end_time` - (Optional) End time of the scheduled task to be repeated. The date format follows the ISO8601 standard and uses UTC time. It is in the format of YYYY-MM-DDThh:mmZ. A time point 90 days after creation or modification cannot be entered. RecurrenceType, RecurrenceValue and RecurrenceEndTime must be specified. +* `task_enabled` - (Optional) Whether to enable the scheduled task. The default value is true. + + +## Attributes Reference + +The following attributes are exported: + +* `id` - The schedule task ID. +* `scheduled_action` - The action of schedule task. +* `launch_time` - The time of schedule task be triggered. +* `scheduled_task_name` - The name of schedule task. +* `description` - The description of schedule task. +* `task_enabled` - Wether the task is enabled. \ No newline at end of file diff --git a/website/source/docs/providers/alicloud/r/forward.html.markdown b/website/source/docs/providers/alicloud/r/forward.html.markdown new file mode 100644 index 000000000..6024921a6 --- /dev/null +++ b/website/source/docs/providers/alicloud/r/forward.html.markdown @@ -0,0 +1,68 @@ +--- +layout: "alicloud" +page_title: "Alicloud: alicloud_forward_entry" +sidebar_current: "docs-alicloud-resource-vpc" +description: |- + Provides a Alicloud forward resource. +--- + +# alicloud\_forward + +Provides a forward resource. + +## Example Usage + +Basic Usage + +``` +resource "alicloud_vpc" "foo" { + ... +} + +resource "alicloud_vswitch" "foo" { + ... +} + +resource "alicloud_nat_gateway" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + spec = "Small" + name = "test_foo" + + bandwidth_packages = [ + { + ip_count = 2 + bandwidth = 5 + zone = "" + }, + { + ip_count = 1 + bandwidth = 6 + zone = "cn-beijing-b" + } + ] + + depends_on = [ + "alicloud_vswitch.foo", + ] +} + +resource "alicloud_forward_entry" "foo" { + forward_table_id = "${alicloud_nat_gateway.foo.forward_table_ids}" + external_ip = "${alicloud_nat_gateway.foo.bandwidth_packages.0.public_ip_addresses}" + external_port = "80" + ip_protocol = "tcp" + internal_ip = "172.16.0.3" + internal_port = "8080" +} + +``` +## Argument Reference + +The following arguments are supported: + +* `forward_table_id` - (Required, Forces new resource) The value can get from `alicloud_nat_gateway` Attributes "forward_table_ids". +* `external_ip` - (Required, Forces new resource) The external ip address, the ip must along bandwidth package public ip which `alicloud_nat_gateway` argument `bandwidth_packages`. +* `external_port` - (Required) The external port, valid value is 1~65535|any. +* `ip_protocol` - (Required) The ip protocal, valid value is tcp|udp|any. +* `internal_ip` - (Required) The internal ip, must a private ip. +* `internal_port` - (Required) The internal port, valid value is 1~65535|any. \ No newline at end of file diff --git a/website/source/docs/providers/alicloud/r/instance.html.markdown b/website/source/docs/providers/alicloud/r/instance.html.markdown index cb038ed1a..f09473df0 100644 --- a/website/source/docs/providers/alicloud/r/instance.html.markdown +++ b/website/source/docs/providers/alicloud/r/instance.html.markdown @@ -12,7 +12,7 @@ Provides a ECS instance resource. ## Example Usage -```hcl +``` # Create a new ECS instance for classic resource "alicloud_security_group" "classic" { name = "tf_test_foo" @@ -24,7 +24,7 @@ resource "alicloud_instance" "classic" { availability_zone = "cn-beijing-b" security_groups = ["${alicloud_security_group.classic.*.id}"] - allocate_public_ip = "true" + allocate_public_ip = true # series II instance_type = "ecs.n1.medium" @@ -36,11 +36,11 @@ resource "alicloud_instance" "classic" { # Create a new ECS instance for VPC resource "alicloud_vpc" "default" { - # ... + # Other parameters... } resource "alicloud_vswitch" "default" { - # ... + # Other parameters... } resource "alicloud_slb" "vpc" { @@ -59,18 +59,17 @@ The following arguments are supported: * `io_optimized` - (Required) Valid values are `none`, `optimized`, If `optimized`, the launched ECS instance will be I/O optimized. * `security_groups` - (Optional) A list of security group ids to associate with. * `availability_zone` - (Optional) The Zone to start the instance in. -* `instance_name` - (Optional) The name of the ECS. This instance_name can have a string of 2 to 128 characters, must contain only alphanumeric characters or hyphens, such as "-",".","\_", and must not begin or end with a hyphen, and must not begin with http:// or https://. If not specified, +* `instance_name` - (Optional) The name of the ECS. This instance_name can have a string of 2 to 128 characters, must contain only alphanumeric characters or hyphens, such as "-",".","_", and must not begin or end with a hyphen, and must not begin with http:// or https://. If not specified, Terraform will autogenerate a default name is `ECS-Instance`. * `allocate_public_ip` - (Optional) Associate a public ip address with an instance in a VPC or Classic. Boolean value, Default is false. -* `system_disk_category` - (Optional) Valid values are `cloud`, `cloud_efficiency`, `cloud_ssd`, For I/O optimized instance type, `cloud_ssd` and `cloud_efficiency` disks are supported. For non I/O Optimized instance type, `cloud` disk are supported. +* `system_disk_category` - (Optional) Valid values are `cloud`, `cloud_efficiency`, `cloud_ssd`, For I/O optimized instance type, `cloud_ssd` and `cloud_efficiency` disks are supported. For non I/O Optimized instance type, `cloud` disk are supported. * `system_disk_size` - (Optional) Size of the system disk, value range: 40GB ~ 500GB. Default is 40GB. * `description` - (Optional) Description of the instance, This description can have a string of 2 to 256 characters, It cannot begin with http:// or https://. Default value is null. * `internet_charge_type` - (Optional) Internet charge type of the instance, Valid values are `PayByBandwidth`, `PayByTraffic`. Default is `PayByBandwidth`. * `internet_max_bandwidth_in` - (Optional) Maximum incoming bandwidth from the public network, measured in Mbps (Mega bit per second). Value range: [1, 200]. If this value is not specified, then automatically sets it to 200 Mbps. -* `internet_max_bandwidth_out` - (Optional) Maximum outgoing bandwidth to the public network, measured in Mbps (Mega bit per second). Value range: -`internet_charge_type` is `PayByBandwidth`: this value range [0, 100], If this value is not specified, then automatically sets it to 0 Mbps; If `internet_charge_type` is `PayByTraffic`: this value range [1, 100]. this value must be set value, such as 5. -* `host_name` - (Optional) Host name of the ECS, which is a string of at least two characters. "hostname” cannot start or end with ".” or "-". In addition, two or more consecutive ".” or "-" symbols are not allowed. On Windows, the host name can contain a maximum of 15 characters, which can be a combination of uppercase/lowercase letters, numerals, and "-". The host name cannot contain dots (".”) or contain only numeric characters. -On other OSs such as Linux, the host name can contain a maximum of 30 characters, which can be segments separated by dots (".”), where each segment can contain uppercase/lowercase letters, numerals, or "\_". +* `internet_max_bandwidth_out` - (Optional) Maximum outgoing bandwidth to the public network, measured in Mbps (Mega bit per second). Value range: [0, 100], If this value is not specified, then automatically sets it to 0 Mbps. +* `host_name` - (Optional) Host name of the ECS, which is a string of at least two characters. “hostname” cannot start or end with “.” or “-“. In addition, two or more consecutive “.” or “-“ symbols are not allowed. On Windows, the host name can contain a maximum of 15 characters, which can be a combination of uppercase/lowercase letters, numerals, and “-“. The host name cannot contain dots (“.”) or contain only numeric characters. +On other OSs such as Linux, the host name can contain a maximum of 30 characters, which can be segments separated by dots (“.”), where each segment can contain uppercase/lowercase letters, numerals, or “_“. * `password` - (Optional) Password to an instance is a string of 8 to 30 characters. It must contain uppercase/lowercase letters and numerals, but cannot contain special symbols. * `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. * `instance_charge_type` - (Optional) Valid values are `PrePaid`, `PostPaid`, The default is `PostPaid`. @@ -94,4 +93,4 @@ The following attributes are exported: * `private_ip` - The instance private ip. * `public_ip` - The instance public ip. * `vswitch_id` - If the instance created in VPC, then this value is virtual switch ID. -* `tags` - The instance tags, use jsonencode(item) to display the value. +* `tags` - The instance tags, use jsonencode(item) to display the value. \ No newline at end of file diff --git a/website/source/docs/providers/alicloud/r/nat_gateway.html.markdown b/website/source/docs/providers/alicloud/r/nat_gateway.html.markdown index 659bd7d1f..33ceb6e9b 100644 --- a/website/source/docs/providers/alicloud/r/nat_gateway.html.markdown +++ b/website/source/docs/providers/alicloud/r/nat_gateway.html.markdown @@ -6,15 +6,18 @@ description: |- Provides a resource to create a VPC NAT Gateway. --- -# alicloud_nat_gateway +# alicloud\_nat\_gateway Provides a resource to create a VPC NAT Gateway. +~> **NOTE:** alicloud_nat_gateway must depends on alicloud_vswitch. + + ## Example Usage Basic usage -```hcl +``` resource "alicloud_vpc" "vpc" { name = "tf_test_foo" cidr_block = "172.16.0.0/12" @@ -31,12 +34,11 @@ resource "alicloud_nat_gateway" "nat_gateway" { spec = "Small" name = "test_foo" - bandwidth_packages = [ - { - ip_count = 1 - bandwidth = 5 - zone = "cn-beijing-b" - }, + bandwidth_packages = [{ + ip_count = 1 + bandwidth = 5 + zone = "cn-beijing-b" + }, { ip_count = 2 bandwidth = 10 @@ -56,7 +58,7 @@ The following arguments are supported: * `vpc_id` - (Required, Forces New Resorce) The VPC ID. * `spec` - (Required, Forces New Resorce) The specification of the nat gateway. Valid values are `Small`, `Middle` and `Large`. Details refer to [Nat Gateway Specification](https://help.aliyun.com/document_detail/42757.html?spm=5176.doc32322.6.559.kFNBzv) -* `name` - (Optional) Name of the nat gateway. The value can have a string of 2 to 128 characters, must contain only alphanumeric characters or hyphens, such as "-",".","\_", and must not begin or end with a hyphen, and must not begin with http:// or https://. Defaults to null. +* `name` - (Optional) Name of the nat gateway. The value can have a string of 2 to 128 characters, must contain only alphanumeric characters or hyphens, such as "-",".","_", and must not begin or end with a hyphen, and must not begin with http:// or https://. Defaults to null. * `description` - (Optional) Description of the nat gateway, This description can have a string of 2 to 256 characters, It cannot begin with http:// or https://. Defaults to null. * `bandwidth_packages` - (Required) A list of bandwidth packages for the nat gatway. @@ -67,6 +69,7 @@ The bandwidth package mapping supports the following: * `ip_count` - (Required) The IP number of the current bandwidth package. Its value range from 1 to 50. * `bandwidth` - (Required) The bandwidth value of the current bandwidth package. Its value range from 5 to 5000. * `zone` - (Optional) The AZ for the current bandwidth. If this value is not specified, Terraform will set a random AZ. +* `public_ip_addresses` - (Computer) The public ip for bandwidth package. the public ip count equal `ip_count`, multi ip would complex with ",", such as "10.0.0.1,10.0.0.2". ## Attributes Reference @@ -78,3 +81,5 @@ The following attributes are exported: * `spec` - The specification of the nat gateway. * `vpc_id` - The VPC ID for the nat gateway. * `bandwidth_package_ids` - A list ID of the bandwidth packages, and split them with commas +* `snat_table_ids` - The nat gateway will auto create a snap and forward item, the `snat_table_ids` is the created one. +* `forward_table_ids` - The nat gateway will auto create a snap and forward item, the `forward_table_ids` is the created one. diff --git a/website/source/docs/providers/alicloud/r/security_group.html.markdown b/website/source/docs/providers/alicloud/r/security_group.html.markdown index 7825d37ae..c25dbe808 100644 --- a/website/source/docs/providers/alicloud/r/security_group.html.markdown +++ b/website/source/docs/providers/alicloud/r/security_group.html.markdown @@ -1,12 +1,12 @@ --- layout: "alicloud" page_title: "Alicloud: alicloud_security_group" -sidebar_current: "docs-alicloud-resource-security-group." +sidebar_current: "docs-alicloud-resource-security-group" description: |- Provides a Alicloud Security Group resource. --- -# alicloud_security_group +# alicloud\_security\_group Provides a security group resource. @@ -16,16 +16,15 @@ Provides a security group resource. Basic Usage -```hcl +``` resource "alicloud_security_group" "group" { name = "terraform-test-group" description = "New security group" } ``` - Basic usage for vpc -```hcl +``` resource "alicloud_security_group" "group" { name = "new-group" vpc_id = "${alicloud_vpc.vpc.id}" @@ -51,4 +50,4 @@ The following attributes are exported: * `id` - The ID of the security group * `vpc_id` - The VPC ID. * `name` - The name of the security group -* `description` - The description of the security group +* `description` - The description of the security group \ No newline at end of file diff --git a/website/source/docs/providers/alicloud/r/security_group_rule.html.markdown b/website/source/docs/providers/alicloud/r/security_group_rule.html.markdown index 2b58aa50f..feaab5b06 100644 --- a/website/source/docs/providers/alicloud/r/security_group_rule.html.markdown +++ b/website/source/docs/providers/alicloud/r/security_group_rule.html.markdown @@ -6,7 +6,7 @@ description: |- Provides a Alicloud Security Group Rule resource. --- -# alicloud_security_group_rule +# alicloud\_security\_group\_rule Provides a security group rule resource. Represents a single `ingress` or `egress` group rule, which can be added to external Security Groups. @@ -18,7 +18,7 @@ Represents a single `ingress` or `egress` group rule, which can be added to exte Basic Usage -```hcl +``` resource "alicloud_security_group" "default" { name = "default" } @@ -58,4 +58,4 @@ The following attributes are exported: * `type` - The type of rule, `ingress` or `egress` * `name` - The name of the security group * `port_range` - The range of port numbers -* `ip_protocol` - The protocol of the security group rule +* `ip_protocol` - The protocol of the security group rule \ No newline at end of file diff --git a/website/source/docs/providers/alicloud/r/slb.html.markdown b/website/source/docs/providers/alicloud/r/slb.html.markdown index b227bc75b..7feb52490 100644 --- a/website/source/docs/providers/alicloud/r/slb.html.markdown +++ b/website/source/docs/providers/alicloud/r/slb.html.markdown @@ -1,18 +1,18 @@ --- layout: "alicloud" page_title: "Alicloud: alicloud_slb" -sidebar_current: "docs-alicloud-resource-slb." +sidebar_current: "docs-alicloud-resource-slb" description: |- Provides an Application Load Banlancer resource. --- -# alicloud_slb +# alicloud\_slb Provides an Application Load Balancer resource. ## Example Usage -```hcl +``` # Create a new load balancer for classic resource "alicloud_slb" "classic" { name = "test-slb-tf" @@ -44,11 +44,11 @@ resource "alicloud_slb" "classic" { # Create a new load balancer for VPC resource "alicloud_vpc" "default" { - # ... + # Other parameters... } resource "alicloud_vswitch" "default" { - # ... + # Other parameters... } resource "alicloud_slb" "vpc" { @@ -62,7 +62,7 @@ resource "alicloud_slb" "vpc" { The following arguments are supported: * `name` - (Optional) The name of the SLB. This name must be unique within your AliCloud account, can have a maximum of 80 characters, -must contain only alphanumeric characters or hyphens, such as "-","/",".","\_", and must not begin or end with a hyphen. If not specified, +must contain only alphanumeric characters or hyphens, such as "-","/",".","_", and must not begin or end with a hyphen. If not specified, Terraform will autogenerate a name beginning with `tf-lb`. * `internet` - (Optional, Forces New Resource) If true, the SLB addressType will be internet, false will be intranet, Default is false. If load balancer launched in VPC, this value must be "false". * `internet_charge_type` - (Optional, Forces New Resource) Valid @@ -74,12 +74,59 @@ Terraform will autogenerate a name beginning with `tf-lb`. ## Block listener +load balance support 4 protocal to listen on, they are `http`,`https`,`tcp`,`udp`, the every listener support which portocal following: + +listener parameter | support protocol | value range | +------------- | ------------- | ------------- | +instance_port | http & https & tcp & udp | 1-65535 | +lb_port | http & https & tcp & udp | 1-65535 | +lb_protocol | http & https & tcp & udp | +bandwidth | http & https & tcp & udp | -1 / 1-1000 | +scheduler | http & https & tcp & udp | wrr or wlc | +sticky_session | http & https | on or off | +sticky_session_type | http & https | insert or server | +cookie_timeout | http & https | 1-86400 | +cookie | http & https | | +persistence_timeout | tcp & udp | 0-3600 | +health_check | http & https | on or off | +health_check_type | tcp | tcp or http | +health_check_domain | http & https & tcp | +health_check_uri | http & https & tcp | | +health_check_connect_port | http & https & tcp & udp | 1-65535 or -520 | +healthy_threshold | http & https & tcp & udp | 1-10 | +unhealthy_threshold | http & https & tcp & udp | 1-10 | +health_check_timeout | http & https & tcp & udp | 1-50 | +health_check_interval | http & https & tcp & udp | 1-5 | +health_check_http_code | http & https & tcp | http_2xx,http_3xx,http_4xx,http_5xx | +ssl_certificate_id | https | | + + The listener mapping supports the following: * `instance_port` - (Required) The port on which the backend servers are listening. Valid value is between 1 to 65535. * `lb_port` - (Required) The port on which the load balancer is listening. Valid value is between 1 to 65535. * `lb_protocol` - (Required) The protocol to listen on. Valid values are `http` and and `tcp` and `udp`. * `bandwidth` - (Required) The bandwidth on which the load balancer is listening. Valid values is -1 or between 1 and 1000. If -1, the bindwidth will haven’t upper limit. +* `scheduler` - (Optinal) Scheduling algorithm, Valid Value is `wrr` / `wlc`, Default is "wrr". +* `sticky_session` - (Optinal) Whether to enable session persistence, Value: `on` / `off`. +* `sticky_session_type` - (Optinal) Mode for handling the cookie. If "sticky_session" is on, the parameter is mandatory, and if "sticky_session" is off, the parameter will be ignored. Value:`insert` / `server`. If it is set to insert, it means it is inserted from Server Load Balancer; and if it is set to server, it means the Server Load Balancer learns from the backend server. +* `cookie_timeout` - (Optinal) The parameter is mandatory when "sticky_session" is on and "sticky_session_type" is insert. Otherwise, it will be ignored. Value: 1-86400(in seconds) +* `cookie` - (Optinal) The cookie configured on the server +It is mandatory only when "sticky_session" is on and "sticky_session_type" is server; otherwise, the parameter will be ignored. Value:String in line with RFC 2965, with length being 1- 200. It only contains characters such as ASCII codes, English letters and digits instead of the comma, semicolon or spacing, and it cannot start with $. +* `persistence_timeout` - (Optinal) Timeout of connection persistence. Value: 0-3600(in seconds) .Default:0 The value 0 indicates to close it. +* `health_check` - (Optinal) Whether to enable health check. Value:`on` / `off` +* `health_check_type` - (Optinal) Type of health check. Value:`tcp` | `http` , Default:`tcp` . TCP supports TCP and HTTP health check mode, you can select the particular mode depending on your application. +* `health_check_domain` - (Optinal) Domain name used for health check. When TCP listener need to use HTTP health check, this parameter will be configured; and when TCP health check is used, the parameter will be ignored. Value: `$_ip | custom string`. Rules of the custom string: its length is limited to 1-80 and only characters such as letters, digits, ‘-‘ and ‘.’ are allowed. When the parameter is set to $_ip by the user, Server Load Balancer uses the private network IP address of each backend server as Domain used for health check. +* `health_check_uri` - (Optinal) URI used for health check. When TCP listener need to use HTTP health check, this parameter will be configured; and when TCP health check is used, the parameter will be ignored. +Value:Its length is limited to 1-80 and it must start with /. Only characters such as letters, digits, ‘-’, ‘/’, ‘.’, ‘%’, ‘?’, #’ and ‘&’ are allowed. +* `health_check_connect_port` - (Optinal) Port used for health check. Value: `1-65535`, Default:None. When the parameter is not set, it means the backend server port is used (BackendServerPort). +* `healthy_threshold` - (Optinal) Threshold determining the result of the health check is success. Value:`1-10`, Default:3. +* `unhealthy_threshold` - (Optinal) Threshold determining the result of the health check is fail. Value:`1-10`, Default:3. +* `health_check_timeout` - (Optinal) Maximum timeout of each health check response. When "health_check" is on, the parameter is mandatory; and when "mandatory" is off, the parameter will be ignored. Value:`1-50`(in seconds). Note: If health_check_timeout < health_check_interval, health_check_timeout is invalid, and the timeout is health_check_interval. +* `health_check_interval` - (Optinal) Time interval of health checks. +When "health_check" is on, the parameter is mandatory; and when "health_check" is off, the parameter will be ignored. Value:`1-5` (in seconds) +* `health_check_http_code` - (Optinal) Regular health check HTTP status code. Multiple codes are segmented by “,”. When "health_check" is on, the parameter is mandatory; and when "health_check" is off, the parameter will be ignored. Value:`http_2xx` / `http_3xx` / `http_4xx` / `http_5xx`. +* `ssl_certificate_id` - (Optinal) Security certificate ID. ## Attributes Reference @@ -91,4 +138,4 @@ The following attributes are exported: * `internet_charge_type` - The internet_charge_type of the load balancer. * `bandwidth` - The bandwidth of the load balancer. * `vswitch_id` - The VSwitch ID of the load balancer. Only available on SLB launched in a VPC. -* `address` - The IP address of the load balancer. +* `address` - The IP address of the load balancer. \ No newline at end of file diff --git a/website/source/docs/providers/alicloud/r/slb_attachment.html.markdown b/website/source/docs/providers/alicloud/r/slb_attachment.html.markdown index 6ae4c1c58..ce3d7ac39 100644 --- a/website/source/docs/providers/alicloud/r/slb_attachment.html.markdown +++ b/website/source/docs/providers/alicloud/r/slb_attachment.html.markdown @@ -6,20 +6,20 @@ description: |- Provides an Application Load Banlancer Attachment resource. --- -# alicloud_slb_attachment +# alicloud\_slb\_attachment Provides an Application Load Balancer Attachment resource. ## Example Usage -```hcl +``` # Create a new load balancer attachment for classic resource "alicloud_slb" "default" { - # ... + # Other parameters... } resource "alicloud_instance" "default" { - # ... + # Other parameters... } resource "alicloud_slb_attachment" "default" { diff --git a/website/source/docs/providers/alicloud/r/snat.html.markdown b/website/source/docs/providers/alicloud/r/snat.html.markdown new file mode 100644 index 000000000..f39549387 --- /dev/null +++ b/website/source/docs/providers/alicloud/r/snat.html.markdown @@ -0,0 +1,61 @@ +--- +layout: "alicloud" +page_title: "Alicloud: alicloud_snat_entry" +sidebar_current: "docs-alicloud-resource-vpc" +description: |- + Provides a Alicloud snat resource. +--- + +# alicloud\_snat + +Provides a snat resource. + +## Example Usage + +Basic Usage + +``` +resource "alicloud_vpc" "foo" { + ... +} + +resource "alicloud_vswitch" "foo" { + ... +} + +resource "alicloud_nat_gateway" "foo" { + vpc_id = "${alicloud_vpc.foo.id}" + spec = "Small" + name = "test_foo" + + bandwidth_packages = [ + { + ip_count = 2 + bandwidth = 5 + zone = "" + }, + { + ip_count = 1 + bandwidth = 6 + zone = "cn-beijing-b" + } + ] + + depends_on = [ + "alicloud_vswitch.foo" + ] +} + +resource "alicloud_snat_entry" "foo" { + snat_table_id = "${alicloud_nat_gateway.foo.snat_table_ids}" + source_vswitch_id = "${alicloud_vswitch.foo.id}" + snat_ip = "${alicloud_nat_gateway.foo.bandwidth_packages.0.public_ip_addresses}" +} +``` +## Argument Reference + +The following arguments are supported: + +* `snat_table_id` - (Required, Forces new resource) The value can get from `alicloud_nat_gateway` Attributes "snat_table_ids". +* `source_vswitch_id` - (Required, Forces new resource) The vswitch ID. +* `snat_ip` - (Required) The SNAT ip address, the ip must along bandwidth package public ip which `alicloud_nat_gateway` argument `bandwidth_packages`. diff --git a/website/source/docs/providers/alicloud/r/vpc.html.markdown b/website/source/docs/providers/alicloud/r/vpc.html.markdown index b7dbc644b..f464326d8 100644 --- a/website/source/docs/providers/alicloud/r/vpc.html.markdown +++ b/website/source/docs/providers/alicloud/r/vpc.html.markdown @@ -16,13 +16,12 @@ Provides a VPC resource. Basic Usage -```hcl +``` resource "alicloud_vpc" "vpc" { name = "tf_test_foo" cidr_block = "172.16.0.0/12" } ``` - ## Argument Reference The following arguments are supported: diff --git a/website/source/docs/providers/alicloud/r/vroute_entry.html.markdown b/website/source/docs/providers/alicloud/r/vroute_entry.html.markdown index a684d1781..adca830be 100644 --- a/website/source/docs/providers/alicloud/r/vroute_entry.html.markdown +++ b/website/source/docs/providers/alicloud/r/vroute_entry.html.markdown @@ -14,7 +14,7 @@ Provides a route entry resource. Basic Usage -```hcl +``` resource "alicloud_vpc" "vpc" { name = "tf_test_foo" cidr_block = "172.16.0.0/12" @@ -29,7 +29,7 @@ resource "alicloud_route_entry" "default" { } resource "alicloud_instance" "snat" { - # ... + // ... } ``` ## Argument Reference diff --git a/website/source/docs/providers/alicloud/r/vswitch.html.markdown b/website/source/docs/providers/alicloud/r/vswitch.html.markdown index 335f5162b..8f6bbdb2f 100644 --- a/website/source/docs/providers/alicloud/r/vswitch.html.markdown +++ b/website/source/docs/providers/alicloud/r/vswitch.html.markdown @@ -6,7 +6,7 @@ description: |- Provides a Alicloud VPC switch resource. --- -# alicloud_vswitch +# alicloud\_vswitch Provides a VPC switch resource. @@ -14,7 +14,7 @@ Provides a VPC switch resource. Basic Usage -```hcl +``` resource "alicloud_vpc" "vpc" { name = "tf_test_foo" cidr_block = "172.16.0.0/12" diff --git a/website/source/layouts/alicloud.erb b/website/source/layouts/alicloud.erb index f582d8324..f6695b85c 100644 --- a/website/source/layouts/alicloud.erb +++ b/website/source/layouts/alicloud.erb @@ -1,75 +1,122 @@ <% wrap_layout :inner do %> - <% content_for :sidebar do %> - + + <% end %> + + <%= yield %> <% end %>