diff --git a/builtin/providers/alicloud/common.go b/builtin/providers/alicloud/common.go index 24c3647db..991cc7fd9 100644 --- a/builtin/providers/alicloud/common.go +++ b/builtin/providers/alicloud/common.go @@ -2,6 +2,7 @@ package alicloud import ( "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ecs" "github.com/hashicorp/terraform/helper/schema" ) @@ -50,3 +51,10 @@ func isProtocalValid(value string) bool { } return res } + +var DefaultBusinessInfo = ecs.BusinessInfo{ + Pack: "terraform", +} + +// default region for all resource +const DEFAULT_REGION = "cn-beijing" diff --git a/builtin/providers/alicloud/config.go b/builtin/providers/alicloud/config.go index 352e2e21c..d3ddda1b4 100644 --- a/builtin/providers/alicloud/config.go +++ b/builtin/providers/alicloud/config.go @@ -19,8 +19,10 @@ type Config struct { type AliyunClient struct { Region common.Region ecsconn *ecs.Client - vpcconn *ecs.Client - slbconn *slb.Client + // use new version + ecsNewconn *ecs.Client + vpcconn *ecs.Client + slbconn *slb.Client } // Client for AliyunClient @@ -35,6 +37,12 @@ func (c *Config) Client() (*AliyunClient, error) { return nil, err } + ecsNewconn, err := c.ecsConn() + if err != nil { + return nil, err + } + ecsNewconn.SetVersion(EcsApiVersion20160314) + slbconn, err := c.slbConn() if err != nil { return nil, err @@ -46,13 +54,27 @@ func (c *Config) Client() (*AliyunClient, error) { } return &AliyunClient{ - Region: c.Region, - ecsconn: ecsconn, - vpcconn: vpcconn, - slbconn: slbconn, + Region: c.Region, + ecsconn: ecsconn, + ecsNewconn: ecsNewconn, + vpcconn: vpcconn, + slbconn: slbconn, }, nil } +// return new ecs Client +// when you need new client not global client, use this method +func (c *Config) NewEcsConn() (*ecs.Client, error) { + client := ecs.NewClient(c.AccessKey, c.SecretKey) + _, err := client.DescribeRegions() + + if err != nil { + return nil, err + } + + return client, nil +} + func (c *Config) loadAndValidate() error { err := c.validateRegion() if err != nil { diff --git a/builtin/providers/alicloud/data_source_alicloud_images.go b/builtin/providers/alicloud/data_source_alicloud_images.go index ae5b66069..d9a873782 100644 --- a/builtin/providers/alicloud/data_source_alicloud_images.go +++ b/builtin/providers/alicloud/data_source_alicloud_images.go @@ -5,10 +5,10 @@ import ( "log" "regexp" "sort" + "time" "github.com/denverdino/aliyungo/ecs" "github.com/hashicorp/terraform/helper/schema" - "time" ) func dataSourceAlicloudImages() *schema.Resource { @@ -175,15 +175,28 @@ func dataSourceAlicloudImagesRead(d *schema.ResourceData, meta interface{}) erro params.ImageOwnerAlias = ecs.ImageOwnerAlias(owners.(string)) } - resp, _, err := conn.DescribeImages(params) - if err != nil { - return err + var allImages []ecs.ImageType + + for { + images, paginationResult, err := conn.DescribeImages(params) + if err != nil { + break + } + + allImages = append(allImages, images...) + + pagination := paginationResult.NextPage() + if pagination == nil { + break + } + + params.Pagination = *pagination } var filteredImages []ecs.ImageType if nameRegexOk { r := regexp.MustCompile(nameRegex.(string)) - for _, image := range resp { + for _, image := range allImages { // Check for a very rare case where the response would include no // image name. No name means nothing to attempt a match against, // therefore we are skipping such image. @@ -198,7 +211,7 @@ func dataSourceAlicloudImagesRead(d *schema.ResourceData, meta interface{}) erro } } } else { - filteredImages = resp[:] + filteredImages = allImages[:] } var images []ecs.ImageType diff --git a/builtin/providers/alicloud/data_source_alicloud_images_test.go b/builtin/providers/alicloud/data_source_alicloud_images_test.go index 7512c6e91..ca7cfe550 100644 --- a/builtin/providers/alicloud/data_source_alicloud_images_test.go +++ b/builtin/providers/alicloud/data_source_alicloud_images_test.go @@ -97,6 +97,22 @@ func TestAccAlicloudImagesDataSource_nameRegexFilter(t *testing.T) { }) } +func TestAccAlicloudImagesDataSource_imageNotInFirstPage(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckAlicloudImagesDataSourceImageNotInFirstPageConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAlicloudDataSourceID("data.alicloud_images.name_regex_filtered_image"), + resource.TestMatchResourceAttr("data.alicloud_images.name_regex_filtered_image", "images.0.image_id", regexp.MustCompile("^ubuntu_1404")), + ), + }, + }, + }) +} + // Instance store test - using centos images const testAccCheckAlicloudImagesDataSourceImagesConfig = ` data "alicloud_images" "multi_image" { @@ -128,3 +144,12 @@ data "alicloud_images" "name_regex_filtered_image" { name_regex = "^centos_6\\w{1,5}[64]{1}.*" } ` + +// Testing image not in first page response +const testAccCheckAlicloudImagesDataSourceImageNotInFirstPageConfig = ` +data "alicloud_images" "name_regex_filtered_image" { + most_recent = true + owners = "system" + name_regex = "^ubuntu_1404\\d{2}_64" +} +` diff --git a/builtin/providers/alicloud/data_source_alicloud_instance_types_test.go b/builtin/providers/alicloud/data_source_alicloud_instance_types_test.go index 43a180def..335da3fbd 100644 --- a/builtin/providers/alicloud/data_source_alicloud_instance_types_test.go +++ b/builtin/providers/alicloud/data_source_alicloud_instance_types_test.go @@ -17,8 +17,6 @@ func TestAccAlicloudInstanceTypesDataSource_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAlicloudDataSourceID("data.alicloud_instance_types.4c8g"), - resource.TestCheckResourceAttr("data.alicloud_instance_types.4c8g", "instance_types.#", "4"), - resource.TestCheckResourceAttr("data.alicloud_instance_types.4c8g", "instance_types.0.cpu_core_count", "4"), resource.TestCheckResourceAttr("data.alicloud_instance_types.4c8g", "instance_types.0.memory_size", "8"), resource.TestCheckResourceAttr("data.alicloud_instance_types.4c8g", "instance_types.0.id", "ecs.s3.large"), diff --git a/builtin/providers/alicloud/data_source_alicloud_regions_test.go b/builtin/providers/alicloud/data_source_alicloud_regions_test.go index f2aff1bbe..603b46101 100644 --- a/builtin/providers/alicloud/data_source_alicloud_regions_test.go +++ b/builtin/providers/alicloud/data_source_alicloud_regions_test.go @@ -71,9 +71,6 @@ func TestAccAlicloudRegionsDataSource_empty(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAlicloudDataSourceID("data.alicloud_regions.empty_params_region"), - resource.TestCheckResourceAttr("data.alicloud_regions.empty_params_region", "name", ""), - resource.TestCheckResourceAttr("data.alicloud_regions.empty_params_region", "current", ""), - resource.TestCheckResourceAttr("data.alicloud_regions.empty_params_region", "regions.#", "13"), resource.TestCheckResourceAttr("data.alicloud_regions.empty_params_region", "regions.0.id", "cn-shenzhen"), diff --git a/builtin/providers/alicloud/data_source_alicloud_zones_test.go b/builtin/providers/alicloud/data_source_alicloud_zones_test.go index 4b07c9671..c15c9e13f 100644 --- a/builtin/providers/alicloud/data_source_alicloud_zones_test.go +++ b/builtin/providers/alicloud/data_source_alicloud_zones_test.go @@ -1,7 +1,10 @@ package alicloud import ( + "fmt" "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "strconv" "testing" ) @@ -23,6 +26,35 @@ func TestAccAlicloudZonesDataSource_basic(t *testing.T) { } func TestAccAlicloudZonesDataSource_filter(t *testing.T) { + // the zone length changed occasionally + // check by range to avoid test case failure + testCheckZoneLength := func(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + ms := s.RootModule() + rs, ok := ms.Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + is := rs.Primary + if is == nil { + return fmt.Errorf("No primary instance: %s", name) + } + + i, err := strconv.Atoi(is.Attributes["zones.#"]) + + if err != nil { + return fmt.Errorf("convert zone length err: %#v", err) + } + + if i <= 0 { + return fmt.Errorf("zone length expected greater than 0 got err: %d", i) + } + + return nil + } + } + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) @@ -33,7 +65,7 @@ func TestAccAlicloudZonesDataSource_filter(t *testing.T) { Config: testAccCheckAlicloudZonesDataSourceFilter, Check: resource.ComposeTestCheckFunc( testAccCheckAlicloudDataSourceID("data.alicloud_zones.foo"), - resource.TestCheckResourceAttr("data.alicloud_zones.foo", "zones.#", "2"), + testCheckZoneLength("data.alicloud_zones.foo"), ), }, @@ -41,7 +73,7 @@ func TestAccAlicloudZonesDataSource_filter(t *testing.T) { Config: testAccCheckAlicloudZonesDataSourceFilterIoOptimized, Check: resource.ComposeTestCheckFunc( testAccCheckAlicloudDataSourceID("data.alicloud_zones.foo"), - resource.TestCheckResourceAttr("data.alicloud_zones.foo", "zones.#", "1"), + testCheckZoneLength("data.alicloud_zones.foo"), ), }, }, diff --git a/builtin/providers/alicloud/extension_ecs.go b/builtin/providers/alicloud/extension_ecs.go index 091bd9708..df21138bf 100644 --- a/builtin/providers/alicloud/extension_ecs.go +++ b/builtin/providers/alicloud/extension_ecs.go @@ -30,3 +30,8 @@ const ( GroupRulePolicyAccept = GroupRulePolicy("accept") GroupRulePolicyDrop = GroupRulePolicy("drop") ) + +const ( + EcsApiVersion20160314 = "2016-03-14" + EcsApiVersion20140526 = "2014-05-26" +) diff --git a/builtin/providers/alicloud/provider.go b/builtin/providers/alicloud/provider.go index 907f3271d..550c34da0 100644 --- a/builtin/providers/alicloud/provider.go +++ b/builtin/providers/alicloud/provider.go @@ -26,7 +26,7 @@ func Provider() terraform.ResourceProvider { "region": &schema.Schema{ Type: schema.TypeString, Required: true, - DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_REGION", "cn-beijing"), + DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_REGION", DEFAULT_REGION), Description: descriptions["region"], }, }, diff --git a/builtin/providers/alicloud/resource_alicloud_disk_test.go b/builtin/providers/alicloud/resource_alicloud_disk_test.go index 6cb55bd8e..b8d73a662 100644 --- a/builtin/providers/alicloud/resource_alicloud_disk_test.go +++ b/builtin/providers/alicloud/resource_alicloud_disk_test.go @@ -136,9 +136,13 @@ func testAccCheckDiskDestroy(s *terraform.State) error { } const testAccDiskConfig = ` +data "alicloud_zones" "default" { + "available_disk_category"= "cloud_efficiency" +} + resource "alicloud_disk" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" name = "New-disk" description = "Hello ecs disk." category = "cloud_efficiency" @@ -146,10 +150,15 @@ resource "alicloud_disk" "foo" { } ` const testAccDiskConfigWithTags = ` +data "alicloud_zones" "default" { + "available_disk_category"= "cloud_efficiency" +} + resource "alicloud_disk" "bar" { # cn-beijing - availability_zone = "cn-beijing-b" - size = "10" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" + category = "cloud_efficiency" + size = "20" tags { Name = "TerraformTest" } diff --git a/builtin/providers/alicloud/resource_alicloud_instance.go b/builtin/providers/alicloud/resource_alicloud_instance.go index aeac4b3af..f209d346d 100644 --- a/builtin/providers/alicloud/resource_alicloud_instance.go +++ b/builtin/providers/alicloud/resource_alicloud_instance.go @@ -5,6 +5,7 @@ import ( "log" "encoding/base64" + "encoding/json" "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/ecs" "github.com/hashicorp/terraform/helper/schema" @@ -21,8 +22,9 @@ func resourceAliyunInstance() *schema.Resource { Schema: map[string]*schema.Schema{ "availability_zone": &schema.Schema{ Type: schema.TypeString, - Required: true, + Optional: true, ForceNew: true, + Computed: true, }, "image_id": &schema.Schema{ @@ -61,8 +63,11 @@ func resourceAliyunInstance() *schema.Resource { }, "instance_network_type": &schema.Schema{ - Type: schema.TypeString, - Computed: true, + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ValidateFunc: validateInstanceNetworkType, }, "internet_charge_type": &schema.Schema{ @@ -145,7 +150,6 @@ func resourceAliyunInstance() *schema.Resource { "private_ip": &schema.Schema{ Type: schema.TypeString, - Optional: true, Computed: true, }, @@ -168,6 +172,11 @@ func resourceAliyunInstance() *schema.Resource { func resourceAliyunInstanceCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AliyunClient).ecsconn + // create postpaid instance by runInstances API + if v := d.Get("instance_charge_type").(string); v != string(common.PrePaid) { + return resourceAliyunRunInstance(d, meta) + } + args, err := buildAliyunInstanceArgs(d, meta) if err != nil { return err @@ -207,6 +216,49 @@ func resourceAliyunInstanceCreate(d *schema.ResourceData, meta interface{}) erro return resourceAliyunInstanceUpdate(d, meta) } +func resourceAliyunRunInstance(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AliyunClient).ecsconn + newConn := meta.(*AliyunClient).ecsNewconn + + args, err := buildAliyunInstanceArgs(d, meta) + if err != nil { + return err + } + + runArgs, err := buildAliyunRunInstancesArgs(d, meta) + if err != nil { + return err + } + + runArgs.CreateInstanceArgs = *args + + // runInstances is support in version 2016-03-14 + instanceIds, err := newConn.RunInstances(runArgs) + + if err != nil { + return fmt.Errorf("Error creating Aliyun ecs instance: %#v", err) + } + + d.SetId(instanceIds[0]) + + d.Set("password", d.Get("password")) + d.Set("system_disk_category", d.Get("system_disk_category")) + + 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) + } + } + + // after instance created, its status change from pending, starting to running + 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) +} + func resourceAliyunInstanceRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*AliyunClient) conn := client.ecsconn @@ -414,33 +466,68 @@ func resourceAliyunInstanceDelete(d *schema.ResourceData, meta interface{}) erro return nil } +func buildAliyunRunInstancesArgs(d *schema.ResourceData, meta interface{}) (*ecs.RunInstanceArgs, error) { + args := &ecs.RunInstanceArgs{ + MaxAmount: 1, + MinAmount: 1, + } + + bussStr, err := json.Marshal(DefaultBusinessInfo) + if err != nil { + log.Printf("Failed to translate bussiness info %#v from json to string", DefaultBusinessInfo) + } + + args.BusinessInfo = string(bussStr) + + subnetValue := d.Get("subnet_id").(string) + vswitchValue := d.Get("vswitch_id").(string) + networkValue := d.Get("instance_network_type").(string) + + // because runInstance is not compatible with createInstance, force NetworkType value to classic + if subnetValue == "" && vswitchValue == "" && networkValue == "" { + args.NetworkType = string(ClassicNet) + } + + return args, nil +} func buildAliyunInstanceArgs(d *schema.ResourceData, meta interface{}) (*ecs.CreateInstanceArgs, error) { client := meta.(*AliyunClient) args := &ecs.CreateInstanceArgs{ - RegionId: getRegion(d, meta), - InstanceType: d.Get("instance_type").(string), - PrivateIpAddress: d.Get("private_ip").(string), + RegionId: getRegion(d, meta), + InstanceType: d.Get("instance_type").(string), } imageID := d.Get("image_id").(string) args.ImageId = imageID + systemDiskCategory := ecs.DiskCategory(d.Get("system_disk_category").(string)) + zoneID := d.Get("availability_zone").(string) + // check instanceType and systemDiskCategory, when zoneID is not empty + if zoneID != "" { + zone, err := client.DescribeZone(zoneID) + if err != nil { + return nil, err + } + + if err := client.ResourceAvailable(zone, ecs.ResourceTypeInstance); err != nil { + return nil, err + } + + if err := client.DiskAvailable(zone, systemDiskCategory); err != nil { + return nil, err + } + + args.ZoneId = zoneID - zone, err := client.DescribeZone(zoneID) - if err != nil { - return nil, err } - - if err := client.ResourceAvailable(zone, ecs.ResourceTypeInstance); err != nil { - return nil, err + args.SystemDisk = ecs.SystemDiskType{ + Category: systemDiskCategory, } - args.ZoneId = zoneID - sgs, ok := d.GetOk("security_groups") if ok { @@ -454,16 +541,6 @@ func buildAliyunInstanceArgs(d *schema.ResourceData, meta interface{}) (*ecs.Cre } - systemDiskCategory := ecs.DiskCategory(d.Get("system_disk_category").(string)) - - if err := client.DiskAvailable(zone, systemDiskCategory); err != nil { - return nil, err - } - - args.SystemDisk = ecs.SystemDiskType{ - Category: systemDiskCategory, - } - if v := d.Get("instance_name").(string); v != "" { args.InstanceName = v } @@ -490,7 +567,11 @@ func buildAliyunInstanceArgs(d *schema.ResourceData, meta interface{}) (*ecs.Cre } if v := d.Get("io_optimized").(string); v != "" { - args.IoOptimized = ecs.IoOptimized(v) + if v == "optimized" { + args.IoOptimized = ecs.IoOptimized("true") + } else { + args.IoOptimized = ecs.IoOptimized("false") + } } vswitchValue := d.Get("subnet_id").(string) diff --git a/builtin/providers/alicloud/resource_alicloud_instance_test.go b/builtin/providers/alicloud/resource_alicloud_instance_test.go index 2fb232f3c..1df3cbd6d 100644 --- a/builtin/providers/alicloud/resource_alicloud_instance_test.go +++ b/builtin/providers/alicloud/resource_alicloud_instance_test.go @@ -355,10 +355,6 @@ func TestAccAlicloudInstance_tags(t *testing.T) { Config: testAccCheckInstanceConfigTagsUpdate, Check: resource.ComposeTestCheckFunc( testAccCheckInstanceExists("alicloud_instance.foo", &instance), - resource.TestCheckResourceAttr( - "alicloud_instance.foo", - "tags.foo", - ""), resource.TestCheckResourceAttr( "alicloud_instance.foo", "tags.bar", @@ -418,8 +414,8 @@ func TestAccAlicloudInstance_privateIP(t *testing.T) { testCheckPrivateIP := func() resource.TestCheckFunc { return func(*terraform.State) error { privateIP := instance.VpcAttributes.PrivateIpAddress.IpAddress[0] - if privateIP != "172.16.0.229" { - return fmt.Errorf("bad private IP: %s", privateIP) + if privateIP == "" { + return fmt.Errorf("can't get private IP") } return nil @@ -445,14 +441,14 @@ func TestAccAlicloudInstance_privateIP(t *testing.T) { }) } -func TestAccAlicloudInstance_associatePublicIPAndPrivateIP(t *testing.T) { +func TestAccAlicloudInstance_associatePublicIP(t *testing.T) { var instance ecs.InstanceAttributesType testCheckPrivateIP := func() resource.TestCheckFunc { return func(*terraform.State) error { privateIP := instance.VpcAttributes.PrivateIpAddress.IpAddress[0] - if privateIP != "172.16.0.229" { - return fmt.Errorf("bad private IP: %s", privateIP) + if privateIP == "" { + return fmt.Errorf("can't get private IP") } return nil @@ -468,7 +464,7 @@ func TestAccAlicloudInstance_associatePublicIPAndPrivateIP(t *testing.T) { CheckDestroy: testAccCheckInstanceDestroy, Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccInstanceConfigAssociatePublicIPAndPrivateIP, + Config: testAccInstanceConfigAssociatePublicIP, Check: resource.ComposeTestCheckFunc( testAccCheckInstanceExists("alicloud_instance.foo", &instance), testCheckPrivateIP(), @@ -609,8 +605,6 @@ resource "alicloud_security_group" "tf_test_bar" { } resource "alicloud_instance" "foo" { - # cn-beijing - availability_zone = "cn-beijing-b" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" system_disk_category = "cloud_ssd" @@ -628,6 +622,11 @@ resource "alicloud_instance" "foo" { } ` const testAccInstanceConfigVPC = ` +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" @@ -636,7 +635,7 @@ resource "alicloud_vpc" "foo" { resource "alicloud_vswitch" "foo" { vpc_id = "${alicloud_vpc.foo.id}" cidr_block = "172.16.0.0/21" - availability_zone = "cn-beijing-b" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" } resource "alicloud_security_group" "tf_test_foo" { @@ -647,7 +646,6 @@ resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" vswitch_id = "${alicloud_vswitch.foo.id}" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" @@ -666,6 +664,11 @@ resource "alicloud_instance" "foo" { ` const testAccInstanceConfigUserData = ` +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" @@ -674,7 +677,7 @@ resource "alicloud_vpc" "foo" { resource "alicloud_vswitch" "foo" { vpc_id = "${alicloud_vpc.foo.id}" cidr_block = "172.16.0.0/21" - availability_zone = "cn-beijing-b" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" } resource "alicloud_security_group" "tf_test_foo" { @@ -685,7 +688,6 @@ resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" vswitch_id = "${alicloud_vswitch.foo.id}" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" # series II @@ -727,7 +729,6 @@ resource "alicloud_security_group" "tf_test_bar" { resource "alicloud_instance" "foo" { # cn-beijing provider = "alicloud.beijing" - availability_zone = "cn-beijing-b" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" internet_charge_type = "PayByBandwidth" @@ -742,7 +743,6 @@ resource "alicloud_instance" "foo" { resource "alicloud_instance" "bar" { # cn-shanghai provider = "alicloud.shanghai" - availability_zone = "cn-shanghai-b" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" internet_charge_type = "PayByBandwidth" @@ -768,7 +768,6 @@ resource "alicloud_security_group" "tf_test_bar" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" instance_type = "ecs.s2.large" @@ -776,6 +775,7 @@ resource "alicloud_instance" "foo" { security_groups = ["${alicloud_security_group.tf_test_foo.id}", "${alicloud_security_group.tf_test_bar.id}"] instance_name = "test_foo" io_optimized = "optimized" + system_disk_category = "cloud_efficiency" }` const testAccInstanceConfig_multiSecurityGroup_add = ` @@ -796,7 +796,6 @@ resource "alicloud_security_group" "tf_test_add_sg" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" instance_type = "ecs.s2.large" @@ -805,6 +804,7 @@ resource "alicloud_instance" "foo" { "${alicloud_security_group.tf_test_add_sg.id}"] instance_name = "test_foo" io_optimized = "optimized" + system_disk_category = "cloud_efficiency" } ` @@ -816,7 +816,6 @@ resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" instance_type = "ecs.s2.large" @@ -824,6 +823,7 @@ resource "alicloud_instance" "foo" { security_groups = ["${alicloud_security_group.tf_test_foo.id}"] instance_name = "test_foo" io_optimized = "optimized" + system_disk_category = "cloud_efficiency" } ` @@ -836,18 +836,23 @@ resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" instance_type = "ecs.s2.large" internet_charge_type = "PayByBandwidth" security_groups = ["${alicloud_security_group.tf_test_foo.*.id}"] instance_name = "test_foo" - io_optimized = "none" + io_optimized = "optimized" + system_disk_category = "cloud_efficiency" } ` const testAccInstanceNetworkInstanceSecurityGroups = ` +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" @@ -856,7 +861,7 @@ resource "alicloud_vpc" "foo" { resource "alicloud_vswitch" "foo" { vpc_id = "${alicloud_vpc.foo.id}" cidr_block = "172.16.0.0/21" - availability_zone = "cn-beijing-b" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" } resource "alicloud_security_group" "tf_test_foo" { @@ -867,7 +872,6 @@ resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" vswitch_id = "${alicloud_vswitch.foo.id}" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" @@ -892,7 +896,6 @@ resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" # series II @@ -918,7 +921,6 @@ resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" # series II @@ -943,7 +945,6 @@ resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" # series II @@ -967,7 +968,6 @@ resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" # series II @@ -984,6 +984,11 @@ resource "alicloud_instance" "foo" { ` const testAccInstanceConfigPrivateIP = ` +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" @@ -992,7 +997,7 @@ resource "alicloud_vpc" "foo" { resource "alicloud_vswitch" "foo" { vpc_id = "${alicloud_vpc.foo.id}" cidr_block = "172.16.0.0/24" - availability_zone = "cn-beijing-b" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" } resource "alicloud_security_group" "tf_test_foo" { @@ -1003,11 +1008,9 @@ resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" security_groups = ["${alicloud_security_group.tf_test_foo.id}"] vswitch_id = "${alicloud_vswitch.foo.id}" - private_ip = "172.16.0.229" # series II instance_type = "ecs.n1.medium" @@ -1017,7 +1020,12 @@ resource "alicloud_instance" "foo" { instance_name = "test_foo" } ` -const testAccInstanceConfigAssociatePublicIPAndPrivateIP = ` +const testAccInstanceConfigAssociatePublicIP = ` +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" @@ -1026,7 +1034,7 @@ resource "alicloud_vpc" "foo" { resource "alicloud_vswitch" "foo" { vpc_id = "${alicloud_vpc.foo.id}" cidr_block = "172.16.0.0/24" - availability_zone = "cn-beijing-b" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" } resource "alicloud_security_group" "tf_test_foo" { @@ -1037,11 +1045,9 @@ resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" security_groups = ["${alicloud_security_group.tf_test_foo.id}"] vswitch_id = "${alicloud_vswitch.foo.id}" - private_ip = "172.16.0.229" allocate_public_ip = "true" internet_max_bandwidth_out = 5 internet_charge_type = "PayByBandwidth" @@ -1055,6 +1061,11 @@ resource "alicloud_instance" "foo" { } ` const testAccVpcInstanceWithSecurityRule = ` +data "alicloud_zones" "default" { + "available_disk_category"= "cloud_efficiency" + "available_resource_creation"= "VSwitch" +} + resource "alicloud_vpc" "foo" { name = "tf_test_foo" cidr_block = "10.1.0.0/21" @@ -1063,7 +1074,7 @@ resource "alicloud_vpc" "foo" { resource "alicloud_vswitch" "foo" { vpc_id = "${alicloud_vpc.foo.id}" cidr_block = "10.1.1.0/24" - availability_zone = "cn-beijing-c" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" } resource "alicloud_security_group" "tf_test_foo" { @@ -1085,7 +1096,6 @@ resource "alicloud_security_group_rule" "ingress" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-c" security_groups = ["${alicloud_security_group.tf_test_foo.id}"] vswitch_id = "${alicloud_vswitch.foo.id}" diff --git a/builtin/providers/alicloud/resource_alicloud_nat_gateway_test.go b/builtin/providers/alicloud/resource_alicloud_nat_gateway_test.go index ad8fba166..4f792751f 100644 --- a/builtin/providers/alicloud/resource_alicloud_nat_gateway_test.go +++ b/builtin/providers/alicloud/resource_alicloud_nat_gateway_test.go @@ -151,6 +151,10 @@ func testAccCheckNatGatewayDestroy(s *terraform.State) error { } const testAccNatGatewayConfig = ` +data "alicloud_zones" "default" { + "available_resource_creation"= "VSwitch" +} + resource "alicloud_vpc" "foo" { name = "tf_test_foo" cidr_block = "172.16.0.0/12" @@ -159,7 +163,7 @@ resource "alicloud_vpc" "foo" { resource "alicloud_vswitch" "foo" { vpc_id = "${alicloud_vpc.foo.id}" cidr_block = "172.16.0.0/21" - availability_zone = "cn-beijing-b" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" } resource "alicloud_nat_gateway" "foo" { @@ -169,11 +173,11 @@ resource "alicloud_nat_gateway" "foo" { bandwidth_packages = [{ ip_count = 1 bandwidth = 5 - zone = "cn-beijing-b" + zone = "${data.alicloud_zones.default.zones.0.id}" }, { ip_count = 2 bandwidth = 10 - zone = "cn-beijing-b" + zone = "${data.alicloud_zones.default.zones.0.id}" }] depends_on = [ "alicloud_vswitch.foo"] @@ -181,6 +185,10 @@ resource "alicloud_nat_gateway" "foo" { ` const testAccNatGatewayConfigSpec = ` +data "alicloud_zones" "default" { + "available_resource_creation"= "VSwitch" +} + resource "alicloud_vpc" "foo" { name = "tf_test_foo" cidr_block = "172.16.0.0/12" @@ -189,7 +197,7 @@ resource "alicloud_vpc" "foo" { resource "alicloud_vswitch" "foo" { vpc_id = "${alicloud_vpc.foo.id}" cidr_block = "172.16.0.0/21" - availability_zone = "cn-beijing-b" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" } resource "alicloud_nat_gateway" "foo" { @@ -199,11 +207,11 @@ resource "alicloud_nat_gateway" "foo" { bandwidth_packages = [{ ip_count = 1 bandwidth = 5 - zone = "cn-beijing-b" + zone = "${data.alicloud_zones.default.zones.0.id}" }, { ip_count = 2 bandwidth = 10 - zone = "cn-beijing-b" + zone = "${data.alicloud_zones.default.zones.0.id}" }] depends_on = [ "alicloud_vswitch.foo"] @@ -211,6 +219,10 @@ resource "alicloud_nat_gateway" "foo" { ` const testAccNatGatewayConfigSpecUpgrade = ` +data "alicloud_zones" "default" { + "available_resource_creation"= "VSwitch" +} + resource "alicloud_vpc" "foo" { name = "tf_test_foo" cidr_block = "172.16.0.0/12" @@ -219,7 +231,7 @@ resource "alicloud_vpc" "foo" { resource "alicloud_vswitch" "foo" { vpc_id = "${alicloud_vpc.foo.id}" cidr_block = "172.16.0.0/21" - availability_zone = "cn-beijing-b" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" } resource "alicloud_nat_gateway" "foo" { @@ -229,11 +241,11 @@ resource "alicloud_nat_gateway" "foo" { bandwidth_packages = [{ ip_count = 1 bandwidth = 5 - zone = "cn-beijing-b" + zone = "${data.alicloud_zones.default.zones.0.id}" }, { ip_count = 2 bandwidth = 10 - zone = "cn-beijing-b" + zone = "${data.alicloud_zones.default.zones.0.id}" }] depends_on = [ "alicloud_vswitch.foo"] diff --git a/builtin/providers/alicloud/resource_alicloud_security_group_rule.go b/builtin/providers/alicloud/resource_alicloud_security_group_rule.go index 4627d8e2b..89cd229be 100644 --- a/builtin/providers/alicloud/resource_alicloud_security_group_rule.go +++ b/builtin/providers/alicloud/resource_alicloud_security_group_rule.go @@ -34,6 +34,7 @@ func resourceAliyunSecurityGroupRule() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, + Computed: true, ValidateFunc: validateSecurityRuleNicType, }, @@ -161,15 +162,28 @@ func resourceAliyunSecurityGroupRuleRead(d *schema.ResourceData, meta interface{ func resourceAliyunSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{}) error { client := meta.(*AliyunClient) - args, err := buildAliyunSecurityIngressArgs(d, meta) + ruleType := d.Get("type").(string) + + if GroupRuleDirection(ruleType) == GroupRuleIngress { + args, err := buildAliyunSecurityIngressArgs(d, meta) + if err != nil { + return err + } + revokeArgs := &ecs.RevokeSecurityGroupArgs{ + AuthorizeSecurityGroupArgs: *args, + } + return client.RevokeSecurityGroup(revokeArgs) + } + + args, err := buildAliyunSecurityEgressArgs(d, meta) if err != nil { return err } - revokeArgs := &ecs.RevokeSecurityGroupArgs{ - AuthorizeSecurityGroupArgs: *args, + revokeArgs := &ecs.RevokeSecurityGroupEgressArgs{ + AuthorizeSecurityGroupEgressArgs: *args, } - return client.RevokeSecurityGroup(revokeArgs) + return client.RevokeSecurityGroupEgress(revokeArgs) } func buildAliyunSecurityIngressArgs(d *schema.ResourceData, meta interface{}) (*ecs.AuthorizeSecurityGroupArgs, error) { diff --git a/builtin/providers/alicloud/resource_alicloud_security_group_rule_test.go b/builtin/providers/alicloud/resource_alicloud_security_group_rule_test.go index 7eb267fcb..42c4d7cfe 100644 --- a/builtin/providers/alicloud/resource_alicloud_security_group_rule_test.go +++ b/builtin/providers/alicloud/resource_alicloud_security_group_rule_test.go @@ -81,6 +81,39 @@ func TestAccAlicloudSecurityGroupRule_Egress(t *testing.T) { } +func TestAccAlicloudSecurityGroupRule_EgressDefaultNicType(t *testing.T) { + var pt ecs.PermissionType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_security_group_rule.egress", + Providers: testAccProviders, + CheckDestroy: testAccCheckSecurityGroupRuleDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccSecurityGroupRuleEgress_emptyNicType, + Check: resource.ComposeTestCheckFunc( + testAccCheckSecurityGroupRuleExists( + "alicloud_security_group_rule.egress", &pt), + resource.TestCheckResourceAttr( + "alicloud_security_group_rule.egress", + "port_range", + "80/80"), + resource.TestCheckResourceAttr( + "alicloud_security_group_rule.egress", + "nic_type", + "internet"), + ), + }, + }, + }) + +} + func TestAccAlicloudSecurityGroupRule_Vpc_Ingress(t *testing.T) { var pt ecs.PermissionType @@ -114,6 +147,43 @@ func TestAccAlicloudSecurityGroupRule_Vpc_Ingress(t *testing.T) { } +func TestAccAlicloudSecurityGroupRule_MissParameterSourceCidrIp(t *testing.T) { + var pt ecs.PermissionType + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + + // module name + IDRefreshName: "alicloud_security_group_rule.egress", + Providers: testAccProviders, + CheckDestroy: testAccCheckSecurityGroupRuleDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccSecurityGroupRule_missingSourceCidrIp, + Check: resource.ComposeTestCheckFunc( + testAccCheckSecurityGroupRuleExists( + "alicloud_security_group_rule.egress", &pt), + resource.TestCheckResourceAttr( + "alicloud_security_group_rule.egress", + "port_range", + "80/80"), + resource.TestCheckResourceAttr( + "alicloud_security_group_rule.egress", + "nic_type", + "internet"), + resource.TestCheckResourceAttr( + "alicloud_security_group_rule.egress", + "ip_protocol", + "udp"), + ), + }, + }, + }) + +} + func testAccCheckSecurityGroupRuleExists(n string, m *ecs.PermissionType) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -210,6 +280,23 @@ resource "alicloud_security_group_rule" "egress" { ` +const testAccSecurityGroupRuleEgress_emptyNicType = ` +resource "alicloud_security_group" "foo" { + name = "sg_foo" +} + +resource "alicloud_security_group_rule" "egress" { + type = "egress" + ip_protocol = "udp" + policy = "accept" + port_range = "80/80" + priority = 1 + security_group_id = "${alicloud_security_group.foo.id}" + cidr_ip = "10.159.6.18/12" +} + +` + const testAccSecurityGroupRuleVpcIngress = ` resource "alicloud_security_group" "foo" { vpc_id = "${alicloud_vpc.vpc.id}" @@ -231,6 +318,22 @@ resource "alicloud_security_group_rule" "ingress" { cidr_ip = "10.159.6.18/12" } +` +const testAccSecurityGroupRule_missingSourceCidrIp = ` +resource "alicloud_security_group" "foo" { + name = "sg_foo" +} + +resource "alicloud_security_group_rule" "egress" { + security_group_id = "${alicloud_security_group.foo.id}" + type = "egress" + cidr_ip= "0.0.0.0/0" + policy = "accept" + ip_protocol= "udp" + port_range= "80/80" + priority= 1 +} + ` const testAccSecurityGroupRuleMultiIngress = ` diff --git a/builtin/providers/alicloud/resource_alicloud_slb_attachment_test.go b/builtin/providers/alicloud/resource_alicloud_slb_attachment_test.go index 90a70ead8..45410b34c 100644 --- a/builtin/providers/alicloud/resource_alicloud_slb_attachment_test.go +++ b/builtin/providers/alicloud/resource_alicloud_slb_attachment_test.go @@ -81,7 +81,6 @@ resource "alicloud_security_group" "foo" { resource "alicloud_instance" "foo" { # cn-beijing - availability_zone = "cn-beijing-b" image_id = "ubuntu_140405_64_40G_cloudinit_20161115.vhd" # series II diff --git a/builtin/providers/alicloud/resource_alicloud_slb_test.go b/builtin/providers/alicloud/resource_alicloud_slb_test.go index 3e68a4c14..0502f78de 100644 --- a/builtin/providers/alicloud/resource_alicloud_slb_test.go +++ b/builtin/providers/alicloud/resource_alicloud_slb_test.go @@ -275,6 +275,10 @@ resource "alicloud_slb" "listener" { ` const testAccSlb4Vpc = ` +data "alicloud_zones" "default" { + "available_resource_creation"= "VSwitch" +} + resource "alicloud_vpc" "foo" { name = "tf_test_foo" cidr_block = "172.16.0.0/12" @@ -283,7 +287,7 @@ resource "alicloud_vpc" "foo" { resource "alicloud_vswitch" "foo" { vpc_id = "${alicloud_vpc.foo.id}" cidr_block = "172.16.0.0/21" - availability_zone = "cn-beijing-b" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" } resource "alicloud_slb" "vpc" { diff --git a/builtin/providers/alicloud/resource_alicloud_vswitch_test.go b/builtin/providers/alicloud/resource_alicloud_vswitch_test.go index bcd70a2cc..1a1a75bd6 100644 --- a/builtin/providers/alicloud/resource_alicloud_vswitch_test.go +++ b/builtin/providers/alicloud/resource_alicloud_vswitch_test.go @@ -92,6 +92,10 @@ func testAccCheckVswitchDestroy(s *terraform.State) error { } const testAccVswitchConfig = ` +data "alicloud_zones" "default" { + "available_resource_creation"= "VSwitch" +} + resource "alicloud_vpc" "foo" { name = "tf_test_foo" cidr_block = "172.16.0.0/12" @@ -100,6 +104,6 @@ resource "alicloud_vpc" "foo" { resource "alicloud_vswitch" "foo" { vpc_id = "${alicloud_vpc.foo.id}" cidr_block = "172.16.0.0/21" - availability_zone = "cn-beijing-b" + availability_zone = "${data.alicloud_zones.default.zones.0.id}" } ` diff --git a/builtin/providers/alicloud/service_alicloud_ecs.go b/builtin/providers/alicloud/service_alicloud_ecs.go index 2c892ce24..680b3bb61 100644 --- a/builtin/providers/alicloud/service_alicloud_ecs.go +++ b/builtin/providers/alicloud/service_alicloud_ecs.go @@ -187,14 +187,13 @@ func (client *AliyunClient) DescribeSecurity(securityGroupId string) (*ecs.Descr } func (client *AliyunClient) DescribeSecurityGroupRule(securityGroupId, types, ip_protocol, port_range string) (*ecs.PermissionType, error) { - sg, err := client.DescribeSecurity(securityGroupId) if err != nil { return nil, err } for _, p := range sg.Permissions.Permission { - if strings.ToLower(string(p.IpProtocol)) == ip_protocol && p.PortRange == port_range { + if strings.ToLower(string(p.IpProtocol)) == ip_protocol && p.PortRange == port_range && strings.ToLower(p.Direction) == types { return &p, nil } } @@ -203,6 +202,11 @@ func (client *AliyunClient) DescribeSecurityGroupRule(securityGroupId, types, ip } func (client *AliyunClient) RevokeSecurityGroup(args *ecs.RevokeSecurityGroupArgs) error { - //todo: handle the specal err + //when the rule is not exist, api will return success(200) return client.ecsconn.RevokeSecurityGroup(args) } + +func (client *AliyunClient) RevokeSecurityGroupEgress(args *ecs.RevokeSecurityGroupEgressArgs) error { + //when the rule is not exist, api will return success(200) + return client.ecsconn.RevokeSecurityGroupEgress(args) +} diff --git a/examples/alicloud-ecs-nat/README.md b/examples/alicloud-ecs-nat/README.md new file mode 100644 index 000000000..123faebd0 --- /dev/null +++ b/examples/alicloud-ecs-nat/README.md @@ -0,0 +1,33 @@ +### Configure NAT instance Example + +In the Virtual Private Cloud(VPC) environment, to enable multiple back-end intranet hosts to provide services externally with a limited number of EIPs, map the ports on the EIP-bound host to the back-end intranet hosts. + +### Get up and running + +* Planning phase + + terraform plan + +* Apply phase + + terraform apply + + Get the outputs: + + nat_instance_eip_address = 123.56.19.238 + + nat_instance_private_ip = 10.1.1.57 + + worker_instance_private_ip = 10.1.1.56 + +* Apply phase + + + login the vm: ssh root@123.56.19.238|Test123456 + + Run the "iptables -t nat -nvL" command to check the result + + | prot | in | source | destination | | + | ---- | -- | ----------- | -------------- | ------------------------ | + | tcp | * | 0.0.0.0/0 | 10.1.1.57 | tcp dpt:80 to:10.1.1.56 + | all | * | 10.1.1.0/24 | 0.0.0.0/0 | to:10.1.1.57 + + +* Destroy + + terraform destroy \ No newline at end of file diff --git a/examples/alicloud-ecs-nat/main.tf b/examples/alicloud-ecs-nat/main.tf new file mode 100644 index 000000000..300f09746 --- /dev/null +++ b/examples/alicloud-ecs-nat/main.tf @@ -0,0 +1,98 @@ +resource "alicloud_vpc" "main" { + cidr_block = "${var.vpc_cidr}" +} + +resource "alicloud_vswitch" "main" { + vpc_id = "${alicloud_vpc.main.id}" + cidr_block = "${var.vswitch_cidr}" + availability_zone = "${var.zone}" + depends_on = ["alicloud_vpc.main"] +} + +resource "alicloud_route_entry" "entry" { + router_id = "${alicloud_vpc.main.router_id}" + route_table_id = "${alicloud_vpc.main.router_table_id}" + destination_cidrblock = "0.0.0.0/0" + nexthop_type = "Instance" + nexthop_id = "${alicloud_instance.nat.id}" +} + +resource "alicloud_instance" "nat" { + image_id = "${var.image}" + instance_type = "${var.instance_nat_type}" + availability_zone = "${var.zone}" + security_groups = ["${alicloud_security_group.group.id}"] + vswitch_id = "${alicloud_vswitch.main.id}" + instance_name = "nat" + io_optimized = "optimized" + system_disk_category = "cloud_efficiency" + password= "${var.instance_pwd}" + + depends_on = ["alicloud_instance.worker"] + user_data = "${data.template_file.shell.rendered}" + + tags { + Name = "ecs-nat" + } +} + +data "template_file" "shell" { + template = "${file("userdata.sh")}" + + vars { + worker_private_ip = "${alicloud_instance.worker.private_ip}" + vswitch_cidr = "${var.vswitch_cidr}" + } +} + +resource "alicloud_instance" "worker" { + image_id = "${var.image}" + instance_type = "${var.instance_worker_type}" + availability_zone = "${var.zone}" + security_groups = ["${alicloud_security_group.group.id}"] + vswitch_id = "${alicloud_vswitch.main.id}" + instance_name = "worker" + io_optimized = "optimized" + system_disk_category = "cloud_efficiency" + password= "${var.instance_pwd}" + + tags { + Name = "ecs-worker" + } +} + +resource "alicloud_eip" "eip" { +} + +resource "alicloud_eip_association" "attach" { + allocation_id = "${alicloud_eip.eip.id}" + instance_id = "${alicloud_instance.nat.id}" +} + +resource "alicloud_security_group" "group" { + name = "terraform-test-group" + description = "New security group" + vpc_id = "${alicloud_vpc.main.id}" +} + +resource "alicloud_security_group_rule" "allow_in" { + security_group_id = "${alicloud_security_group.group.id}" + type = "ingress" + cidr_ip= "0.0.0.0/0" + policy = "accept" + ip_protocol= "all" + nic_type= "intranet" + port_range= "-1/-1" + priority= 1 +} + +resource "alicloud_security_group_rule" "allow_out" { + security_group_id = "${alicloud_security_group.group.id}" + type = "egress" + cidr_ip= "0.0.0.0/0" + policy = "accept" + ip_protocol= "all" + nic_type= "intranet" + port_range= "-1/-1" + priority= 1 +} \ No newline at end of file diff --git a/examples/alicloud-ecs-nat/outputs.tf b/examples/alicloud-ecs-nat/outputs.tf new file mode 100644 index 000000000..46632334d --- /dev/null +++ b/examples/alicloud-ecs-nat/outputs.tf @@ -0,0 +1,19 @@ +output "nat_instance_id" { + value = "${alicloud_instance.nat.id}" +} + +output "nat_instance_private_ip" { + value = "${alicloud_instance.nat.private_ip}" +} + +output "nat_instance_eip_address" { + value = "${alicloud_eip.eip.ip_address}" +} + +output "worker_instance_id" { + value = "${alicloud_instance.worker.id}" +} + +output "worker_instance_private_ip" { + value = "${alicloud_instance.worker.private_ip}" +} \ No newline at end of file diff --git a/examples/alicloud-ecs-nat/userdata.sh b/examples/alicloud-ecs-nat/userdata.sh new file mode 100644 index 000000000..6cf1f4536 --- /dev/null +++ b/examples/alicloud-ecs-nat/userdata.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +PostRouting=${vswitch_cidr} +SourceRouting=`ifconfig eth0|grep inet|awk '{print $2}'|tr -d 'addr:'` +echo ${worker_private_ip}>> /etc/sysctl.conf +echo 'net.ipv4.ip_forward=1'>> /etc/sysctl.conf +sysctl -p +iptables -t nat -I POSTROUTING -s $PostRouting -j SNAT --to-source $SourceRouting +iptables -t nat -I PREROUTING -d $SourceRouting -p tcp --dport 80 -j DNAT --to ${worker_private_ip} \ No newline at end of file diff --git a/examples/alicloud-ecs-nat/variables.tf b/examples/alicloud-ecs-nat/variables.tf new file mode 100644 index 000000000..2ccec3d1a --- /dev/null +++ b/examples/alicloud-ecs-nat/variables.tf @@ -0,0 +1,27 @@ +variable "vpc_cidr" { + default = "10.1.0.0/21" +} + +variable "vswitch_cidr" { + default = "10.1.1.0/24" +} + +variable "zone" { + default = "cn-beijing-c" +} + +variable "image" { + default = "ubuntu_140405_64_40G_cloudinit_20161115.vhd" +} + +variable "instance_nat_type" { + default = "ecs.n1.small" +} + +variable "instance_worker_type" { + default = "ecs.s2.large" +} + +variable "instance_pwd" { + default = "Test123456" +} \ No newline at end of file diff --git a/examples/alicloud-ecs-userdata/main.tf b/examples/alicloud-ecs-userdata/main.tf index 99376325f..b0eacf57d 100644 --- a/examples/alicloud-ecs-userdata/main.tf +++ b/examples/alicloud-ecs-userdata/main.tf @@ -11,27 +11,38 @@ resource "alicloud_vswitch" "vsw" { } resource "alicloud_security_group" "sg" { - name = "tf-sg" - description = "sg" - vpc_id = "${alicloud_vpc.default.id}" + name = "tf-sg" + description = "sg" + vpc_id = "${alicloud_vpc.default.id}" +} + +resource "alicloud_security_group_rule" "allow_ssh" { + security_group_id = "${alicloud_security_group.sg.id}" + type = "ingress" + cidr_ip= "0.0.0.0/0" + policy = "accept" + ip_protocol= "tcp" + port_range= "22/22" + priority= 1 } resource "alicloud_instance" "website" { - # cn-beijing - availability_zone = "${var.zone}" - vswitch_id = "${alicloud_vswitch.vsw.id}" - image_id = "${var.image}" + # cn-beijing + availability_zone = "${var.zone}" + vswitch_id = "${alicloud_vswitch.vsw.id}" + image_id = "${var.image}" - # series II - instance_type = "${var.ecs_type}" - io_optimized = "optimized" - system_disk_category = "cloud_efficiency" + # series II + instance_type = "${var.ecs_type}" + io_optimized = "optimized" + system_disk_category = "cloud_efficiency" - internet_charge_type = "PayByTraffic" - internet_max_bandwidth_out = 5 - allocate_public_ip = true - security_groups = ["${alicloud_security_group.sg.id}"] - instance_name = "test_foo" + internet_charge_type = "PayByTraffic" + internet_max_bandwidth_out = 5 + allocate_public_ip = true + security_groups = ["${alicloud_security_group.sg.id}"] + instance_name = "tf_website" + password= "${var.password}" - user_data = "${file("userdata.sh")}" + user_data = "${file("userdata.sh")}" } diff --git a/examples/alicloud-ecs-userdata/outputs.tf b/examples/alicloud-ecs-userdata/outputs.tf index 7115e9247..2034a7016 100644 --- a/examples/alicloud-ecs-userdata/outputs.tf +++ b/examples/alicloud-ecs-userdata/outputs.tf @@ -1,7 +1,8 @@ -output "hostname" { - value = "${alicloud_instance.website.instance_name}" -} output "ecs_id" { value = "${alicloud_instance.website.id}" +} + +output "ecs_public_ip" { + value = "${alicloud_instance.website.public_ip}" } \ No newline at end of file diff --git a/examples/alicloud-ecs-userdata/variables.tf b/examples/alicloud-ecs-userdata/variables.tf index d8809ad83..5c5475839 100644 --- a/examples/alicloud-ecs-userdata/variables.tf +++ b/examples/alicloud-ecs-userdata/variables.tf @@ -10,6 +10,10 @@ variable "zone" { default = "cn-beijing-b" } +variable "password" { + default = "Test123456" +} + variable "image" { default = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" } diff --git a/examples/alicloud-ecs-zone-type/main.tf b/examples/alicloud-ecs-zone-type/main.tf index c3c21bc9a..b4178b8ee 100644 --- a/examples/alicloud-ecs-zone-type/main.tf +++ b/examples/alicloud-ecs-zone-type/main.tf @@ -5,7 +5,7 @@ data "alicloud_instance_types" "1c2g" { } data "alicloud_zones" "default" { - "available_instance_type"= "${data.alicloud_instance_types.4c8g.instance_types.0.id}" + "available_instance_type"= "${data.alicloud_instance_types.1c2g.instance_types.0.id}" "available_disk_category"= "${var.disk_category}" } diff --git a/examples/alicloud-ecs/main.tf b/examples/alicloud-ecs/main.tf index a6d39a059..596b95ebe 100644 --- a/examples/alicloud-ecs/main.tf +++ b/examples/alicloud-ecs/main.tf @@ -5,7 +5,7 @@ resource "alicloud_security_group" "group" { resource "alicloud_disk" "disk" { - availability_zone = "${var.availability_zones}" + availability_zone = "${alicloud_instance.instance.0.availability_zone}" category = "${var.disk_category}" size = "${var.disk_size}" count = "${var.count}" @@ -17,7 +17,6 @@ resource "alicloud_instance" "instance" { image_id = "${var.image_id}" instance_type = "${var.ecs_type}" count = "${var.count}" - availability_zone = "${var.availability_zones}" security_groups = ["${alicloud_security_group.group.*.id}"] internet_charge_type = "${var.internet_charge_type}" diff --git a/examples/alicloud-ecs/variables.tf b/examples/alicloud-ecs/variables.tf index c663f8dd3..63cf7f123 100644 --- a/examples/alicloud-ecs/variables.tf +++ b/examples/alicloud-ecs/variables.tf @@ -23,9 +23,6 @@ variable "ecs_type" { variable "ecs_password" { default = "Test12345" } -variable "availability_zones" { - default = "cn-beijing-b" -} variable "allocate_public_ip" { default = true } @@ -41,7 +38,7 @@ variable "io_optimized" { } variable "disk_category" { - default = "cloud_ssd" + default = "cloud_efficiency" } variable "disk_size" { default = "40" diff --git a/vendor/github.com/denverdino/aliyungo/common/client.go b/vendor/github.com/denverdino/aliyungo/common/client.go index 1fa43afae..f457053b1 100755 --- a/vendor/github.com/denverdino/aliyungo/common/client.go +++ b/vendor/github.com/denverdino/aliyungo/common/client.go @@ -128,7 +128,8 @@ func (client *Client) Invoke(action string, args interface{}, response interface // Invoke sends the raw HTTP request for ECS services //改进了一下上面那个方法,可以使用各种Http方法 -func (client *Client) InvokeByAnyMethod(method, action string, args interface{}, response interface{}) error { +//2017.1.30 增加了一个path参数,用来拓展访问的地址 +func (client *Client) InvokeByAnyMethod(method, action, path string, args interface{}, response interface{}) error { request := Request{} request.init(client.version, action, client.AccessKeyId) @@ -140,17 +141,18 @@ func (client *Client) InvokeByAnyMethod(method, action string, args interface{}, signature := util.CreateSignatureForRequest(method, &data, client.AccessKeySecret) data.Add("Signature", signature) - // Generate the request URL var ( httpReq *http.Request err error ) if method == http.MethodGet { - requestURL := client.endpoint + "?" + data.Encode() + requestURL := client.endpoint + path + "?" + data.Encode() + //fmt.Println(requestURL) httpReq, err = http.NewRequest(method, requestURL, nil) } else { - httpReq, err = http.NewRequest(method, client.endpoint, strings.NewReader(data.Encode())) + //fmt.Println(client.endpoint + path) + httpReq, err = http.NewRequest(method, client.endpoint + path, strings.NewReader(data.Encode())) httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded") } diff --git a/vendor/github.com/denverdino/aliyungo/ecs/images.go b/vendor/github.com/denverdino/aliyungo/ecs/images.go index c623caf9c..7aa38f702 100644 --- a/vendor/github.com/denverdino/aliyungo/ecs/images.go +++ b/vendor/github.com/denverdino/aliyungo/ecs/images.go @@ -112,6 +112,7 @@ func (client *Client) DescribeImages(args *DescribeImagesArgs) (images []ImageTy type CreateImageArgs struct { RegionId common.Region SnapshotId string + InstanceId string ImageName string ImageVersion string Description string diff --git a/vendor/github.com/denverdino/aliyungo/ecs/instances.go b/vendor/github.com/denverdino/aliyungo/ecs/instances.go index cce16dff4..f983330c7 100644 --- a/vendor/github.com/denverdino/aliyungo/ecs/instances.go +++ b/vendor/github.com/denverdino/aliyungo/ecs/instances.go @@ -15,12 +15,14 @@ type InstanceStatus string // Constants of InstanceStatus const ( - Creating = InstanceStatus("Creating") + Creating = InstanceStatus("Creating") // For backward compatability + Pending = InstanceStatus("Pending") Running = InstanceStatus("Running") Starting = InstanceStatus("Starting") Stopped = InstanceStatus("Stopped") Stopping = InstanceStatus("Stopping") + Deleted = InstanceStatus("Deleted") ) type LockReason string @@ -279,6 +281,7 @@ type ModifyInstanceAttributeArgs struct { Description string Password string HostName string + UserData string } type ModifyInstanceAttributeResponse struct { @@ -323,6 +326,37 @@ func (client *Client) WaitForInstance(instanceId string, status InstanceStatus, return nil } +// WaitForInstance waits for instance to given status +// when instance.NotFound wait until timeout +func (client *Client) WaitForInstanceAsyn(instanceId string, status InstanceStatus, timeout int) error { + if timeout <= 0 { + timeout = InstanceDefaultTimeout + } + for { + instance, err := client.DescribeInstanceAttribute(instanceId) + if err != nil { + e, _ := err.(*common.Error) + if e.ErrorResponse.Code != "InvalidInstanceId.NotFound" { + return err + } + continue + } + if instance.Status == status { + //TODO + //Sleep one more time for timing issues + time.Sleep(DefaultWaitForInterval * time.Second) + break + } + timeout = timeout - DefaultWaitForInterval + if timeout <= 0 { + return common.GetClientErrorFromString("Timeout") + } + time.Sleep(DefaultWaitForInterval * time.Second) + + } + return nil +} + type DescribeInstanceVncUrlArgs struct { RegionId common.Region InstanceId string @@ -510,6 +544,43 @@ func (client *Client) CreateInstance(args *CreateInstanceArgs) (instanceId strin return response.InstanceId, err } +type RunInstanceArgs struct { + CreateInstanceArgs + MinAmount int + MaxAmount int + AutoReleaseTime string + NetworkType string + InnerIpAddress string + BusinessInfo string +} + +type RunInstanceResponse struct { + common.Response + InstanceIdSets InstanceIdSets +} + +type InstanceIdSets struct { + InstanceIdSet []string +} + +type BusinessInfo struct { + Pack string `json:"pack,omitempty" yaml:"pack,omitempty"` + ActivityId string `json:"activityId,omitempty" yaml:"activityId,omitempty"` +} + +func (client *Client) RunInstances(args *RunInstanceArgs) (instanceIdSet []string, err error) { + if args.UserData != "" { + // Encode to base64 string + args.UserData = base64.StdEncoding.EncodeToString([]byte(args.UserData)) + } + response := RunInstanceResponse{} + err = client.Invoke("RunInstances", args, &response) + if err != nil { + return nil, err + } + return response.InstanceIdSets.InstanceIdSet, err +} + type SecurityGroupArgs struct { InstanceId string SecurityGroupId string diff --git a/vendor/github.com/denverdino/aliyungo/slb/rules.go b/vendor/github.com/denverdino/aliyungo/slb/rules.go new file mode 100644 index 000000000..d806dafaf --- /dev/null +++ b/vendor/github.com/denverdino/aliyungo/slb/rules.go @@ -0,0 +1,126 @@ +package slb + +import "github.com/denverdino/aliyungo/common" + +type CreateRulesResponse struct { + common.Response +} + +type CreateRulesArgs struct { + RegionId common.Region + LoadBalancerId string + ListenerPort int + RuleList string +} + +type Rule struct { + RuleId string + RuleName string + Domain string + Url string + VServerGroupId string +} + +// Create forward rules +// +// You can read doc at https://help.aliyun.com/document_detail/35226.html?spm=5176.doc35226.6.671.625Omh +func (client *Client) CreateRules(args *CreateRulesArgs) error { + response := CreateRulesResponse{} + err := client.Invoke("CreateRules", args, &response) + if err != nil { + return err + } + return err +} + +type DeleteRulesArgs struct { + RegionId common.Region + RuleIds string +} + +type DeleteRulesResponse struct { + common.Response +} + +// Delete forward rules +// +// You can read doc at https://help.aliyun.com/document_detail/35227.html?spm=5176.doc35226.6.672.6iNBtR +func (client *Client) DeleteRules(args *DeleteRulesArgs) error { + response := DeleteRulesResponse{} + err := client.Invoke("DeleteRules", args, &response) + if err != nil { + return err + } + return err +} + +type SetRuleArgs struct { + RegionId common.Region + RuleId string + VServerGroupId string +} + +type SetRuleResponse struct { + common.Response +} + +// Modify forward rules +// +// You can read doc at https://help.aliyun.com/document_detail/35228.html?spm=5176.doc35227.6.673.rq40a9 +func (client *Client) SetRule(args *SetRuleArgs) error { + response := SetRuleResponse{} + err := client.Invoke("SetRule", args, &response) + if err != nil { + return err + } + return err +} + +type DescribeRuleAttributeArgs struct { + RegionId common.Region + RuleId string +} + +type DescribeRuleAttributeResponse struct { + common.Response + LoadBalancerId string + ListenerPort int + Rule +} + +// Describe rule +// +// You can read doc at https://help.aliyun.com/document_detail/35229.html?spm=5176.doc35226.6.674.DRJeKJ +func (client *Client) DescribeRuleAttribute(args *DescribeRuleAttributeArgs) (*DescribeRuleAttributeResponse, error) { + response := &DescribeRuleAttributeResponse{} + err := client.Invoke("DescribeRuleAttribute", args, response) + if err != nil { + return nil, err + } + return response, nil +} + +type DescribeRulesArgs struct { + RegionId common.Region + LoadBalancerId string + ListenerPort int +} + +type DescribeRulesResponse struct { + common.Response + Rules struct { + Rule []Rule + } +} + +// Describe rule +// +// You can read doc at https://help.aliyun.com/document_detail/35229.html?spm=5176.doc35226.6.674.DRJeKJ +func (client *Client) DescribeRules(args *DescribeRulesArgs) (*DescribeRulesResponse, error) { + response := &DescribeRulesResponse{} + err := client.Invoke("DescribeRules", args, response) + if err != nil { + return nil, err + } + return response, nil +} diff --git a/vendor/vendor.json b/vendor/vendor.json index e047e38c7..9353ad02d 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1292,28 +1292,28 @@ "revisionTime": "2016-10-29T20:57:26Z" }, { - "checksumSHA1": "ADySw3nBHyzEHB6afBSeVRN2A4g=", + "checksumSHA1": "e6yzSIwLwJV0tb2YQupLL0FO1BM=", "path": "github.com/denverdino/aliyungo/common", - "revision": "d123f5d1fa71b211b70b2e9b56a62da21076884a", - "revisionTime": "2017-01-17T10:57:15Z" + "revision": "c0ff6df91f593ae8b30f749cc949b4588d8c96c9", + "revisionTime": "2017-02-23T12:23:33Z" }, { - "checksumSHA1": "9ZY3RlumKp5DAMfL08YwMoOOT2o=", + "checksumSHA1": "YLooG/WAFF61eBUxg/R5cpfi5DE=", "path": "github.com/denverdino/aliyungo/ecs", - "revision": "d123f5d1fa71b211b70b2e9b56a62da21076884a", - "revisionTime": "2017-01-17T10:57:15Z" + "revision": "c0ff6df91f593ae8b30f749cc949b4588d8c96c9", + "revisionTime": "2017-02-23T12:23:33Z" }, { - "checksumSHA1": "QlA7zv05k7HWeR3tg4uHqIlFcg8=", + "checksumSHA1": "mF2UQ4+NJrPUZkm1RNa9Kxr2U0s=", "path": "github.com/denverdino/aliyungo/slb", - "revision": "d123f5d1fa71b211b70b2e9b56a62da21076884a", - "revisionTime": "2017-01-17T10:57:15Z" + "revision": "c0ff6df91f593ae8b30f749cc949b4588d8c96c9", + "revisionTime": "2017-02-23T12:23:33Z" }, { "checksumSHA1": "Lp0KtT7ycgq31ox3Uzhpxyw0U+Y=", "path": "github.com/denverdino/aliyungo/util", - "revision": "d123f5d1fa71b211b70b2e9b56a62da21076884a", - "revisionTime": "2017-01-17T10:57:15Z" + "revision": "c0ff6df91f593ae8b30f749cc949b4588d8c96c9", + "revisionTime": "2017-02-23T12:23:33Z" }, { "checksumSHA1": "yDQQpeUxwqB3C+4opweg6znWJQk=", diff --git a/website/source/docs/providers/alicloud/r/instance.html.markdown b/website/source/docs/providers/alicloud/r/instance.html.markdown index 2d94fff92..afbf2a753 100644 --- a/website/source/docs/providers/alicloud/r/instance.html.markdown +++ b/website/source/docs/providers/alicloud/r/instance.html.markdown @@ -15,38 +15,38 @@ Provides a ECS instance resource. ``` # Create a new ECS instance for classic resource "alicloud_security_group" "classic" { - name = "tf_test_foo" - description = "foo" + name = "tf_test_foo" + description = "foo" } resource "alicloud_instance" "classic" { - # cn-beijing - availability_zone = "cn-beijing-b" - security_group_id = "${alicloud_security_group.classic.id}" + # cn-beijing + availability_zone = "cn-beijing-b" + security_group_id = "${alicloud_security_group.classic.id}" - allocate_public_ip = "true" + allocate_public_ip = "true" - # series II - instance_type = "ecs.n1.medium" - io_optimized = "optimized" - system_disk_category = "cloud_efficiency" - image_id = "ubuntu_140405_64_40G_cloudinit_20161115.vhd" - instance_name = "test_foo" + # series II + instance_type = "ecs.n1.medium" + io_optimized = "optimized" + system_disk_category = "cloud_efficiency" + image_id = "ubuntu_140405_64_40G_cloudinit_20161115.vhd" + instance_name = "test_foo" } # Create a new ECS instance for VPC resource "alicloud_vpc" "default" { - # Other parameters... + # Other parameters... } resource "alicloud_vswitch" "default" { - # Other parameters... + # Other parameters... } resource "alicloud_slb" "vpc" { - name = "test-slb-tf" - vpc_id = "${alicloud_vpc.default.id}" - vswitch_id = "${alicloud_vswitch.default.id}" + name = "test-slb-tf" + vpc_id = "${alicloud_vpc.default.id}" + vswitch_id = "${alicloud_vswitch.default.id}" } ``` @@ -54,22 +54,20 @@ resource "alicloud_slb" "vpc" { The following arguments are supported: -* `availability_zone` - (Required) The Zone to start the instance in. * `image_id` - (Required) The Image to use for the instance. * `instance_type` - (Required) The type of instance to start. -* `security_group_ids` - (Required) A list of security group ids to associate with. If you are creating Instances in a VPC, use `vpc_security_group_ids` instead. -`security_group_ids` instead. -* `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 name beginning with `tf-ecs`. +* `io_optimized` - (Required) Valid values are `none`, `optimized`, If `optimized`, the launched ECS instance will be I/O optimized. +* `security_group_ids` - (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, +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. -* `io_optimized` - (Optional) Valid - values are `none`, `optimized`, If `optimized`, the launched ECS instance will be I/O optimized. Default is `optimized`. -* `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_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 “_“. @@ -77,7 +75,6 @@ On other OSs such as Linux, the host name can contain a maximum of 30 characters * `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`. * `period` - (Optional) The time that you have bought the resource, in month. Only valid when instance_charge_type is set as `PrePaid`. Value range [1, 12]. -* `private_ip` - (Optional) Private IP address to associate with the instance in a VPC. * `tags` - (Optional) A mapping of tags to assign to the resource. ## Attributes Reference