provider alicloud:add new rds resource and some bugs fix (#12913)

* add new rds resource and some bugs fix

* add docs

* fix validator conflix

fix validator conflix
This commit is contained in:
demonwy 2017-03-24 19:04:56 +08:00 committed by Paul Stack
parent 4fe7ee16e6
commit 11768bcf5b
79 changed files with 6976 additions and 546 deletions

View File

@ -2,6 +2,7 @@ package alicloud
import ( import (
"github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
) )
@ -12,8 +13,12 @@ const (
VpcNet = InstanceNetWork("vpc") VpcNet = InstanceNetWork("vpc")
) )
// timeout for common product, ecs e.g.
const defaultTimeout = 120 const defaultTimeout = 120
// timeout for long time progerss product, rds e.g.
const defaultLongTimeout = 800
func getRegion(d *schema.ResourceData, meta interface{}) common.Region { func getRegion(d *schema.ResourceData, meta interface{}) common.Region {
return meta.(*AliyunClient).Region return meta.(*AliyunClient).Region
} }
@ -50,3 +55,26 @@ func isProtocalValid(value string) bool {
} }
return res return res
} }
var DefaultBusinessInfo = ecs.BusinessInfo{
Pack: "terraform",
}
// default region for all resource
const DEFAULT_REGION = "cn-beijing"
// default security ip for db
const DEFAULT_DB_SECURITY_IP = "127.0.0.1"
// we the count of create instance is only one
const DEFAULT_INSTANCE_COUNT = 1
// symbol of multiIZ
const MULTI_IZ_SYMBOL = "MAZ"
// default connect port of db
const DB_DEFAULT_CONNECT_PORT = "3306"
const COMMA_SEPARATED = ","
const LOCAL_HOST_IP = "127.0.0.1"

View File

@ -5,6 +5,7 @@ import (
"github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs" "github.com/denverdino/aliyungo/ecs"
"github.com/denverdino/aliyungo/rds"
"github.com/denverdino/aliyungo/slb" "github.com/denverdino/aliyungo/slb"
) )
@ -19,8 +20,11 @@ type Config struct {
type AliyunClient struct { type AliyunClient struct {
Region common.Region Region common.Region
ecsconn *ecs.Client ecsconn *ecs.Client
vpcconn *ecs.Client rdsconn *rds.Client
slbconn *slb.Client // use new version
ecsNewconn *ecs.Client
vpcconn *ecs.Client
slbconn *slb.Client
} }
// Client for AliyunClient // Client for AliyunClient
@ -35,6 +39,17 @@ func (c *Config) Client() (*AliyunClient, error) {
return nil, err return nil, err
} }
ecsNewconn, err := c.ecsConn()
if err != nil {
return nil, err
}
ecsNewconn.SetVersion(EcsApiVersion20160314)
rdsconn, err := c.rdsConn()
if err != nil {
return nil, err
}
slbconn, err := c.slbConn() slbconn, err := c.slbConn()
if err != nil { if err != nil {
return nil, err return nil, err
@ -46,13 +61,17 @@ func (c *Config) Client() (*AliyunClient, error) {
} }
return &AliyunClient{ return &AliyunClient{
Region: c.Region, Region: c.Region,
ecsconn: ecsconn, ecsconn: ecsconn,
vpcconn: vpcconn, ecsNewconn: ecsNewconn,
slbconn: slbconn, vpcconn: vpcconn,
slbconn: slbconn,
rdsconn: rdsconn,
}, nil }, nil
} }
const BusinessInfoKey = "Terraform"
func (c *Config) loadAndValidate() error { func (c *Config) loadAndValidate() error {
err := c.validateRegion() err := c.validateRegion()
if err != nil { if err != nil {
@ -74,7 +93,9 @@ func (c *Config) validateRegion() error {
} }
func (c *Config) ecsConn() (*ecs.Client, error) { func (c *Config) ecsConn() (*ecs.Client, error) {
client := ecs.NewClient(c.AccessKey, c.SecretKey) client := ecs.NewECSClient(c.AccessKey, c.SecretKey, c.Region)
client.SetBusinessInfo(BusinessInfoKey)
_, err := client.DescribeRegions() _, err := client.DescribeRegions()
if err != nil { if err != nil {
@ -84,20 +105,21 @@ func (c *Config) ecsConn() (*ecs.Client, error) {
return client, nil return client, nil
} }
func (c *Config) slbConn() (*slb.Client, error) { func (c *Config) rdsConn() (*rds.Client, error) {
client := slb.NewClient(c.AccessKey, c.SecretKey) client := rds.NewRDSClient(c.AccessKey, c.SecretKey, c.Region)
client.SetBusinessInfo(BusinessInfoKey)
return client, nil
}
func (c *Config) slbConn() (*slb.Client, error) {
client := slb.NewSLBClient(c.AccessKey, c.SecretKey, c.Region)
client.SetBusinessInfo(BusinessInfoKey)
return client, nil return client, nil
} }
func (c *Config) vpcConn() (*ecs.Client, error) { func (c *Config) vpcConn() (*ecs.Client, error) {
_, err := c.ecsConn() client := ecs.NewVPCClient(c.AccessKey, c.SecretKey, c.Region)
client.SetBusinessInfo(BusinessInfoKey)
if err != nil {
return nil, err
}
client := &ecs.Client{}
client.Init("https://vpc.aliyuncs.com/", "2016-04-28", c.AccessKey, c.SecretKey)
return client, nil return client, nil
} }

View File

@ -5,10 +5,10 @@ import (
"log" "log"
"regexp" "regexp"
"sort" "sort"
"time"
"github.com/denverdino/aliyungo/ecs" "github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"time"
) )
func dataSourceAlicloudImages() *schema.Resource { func dataSourceAlicloudImages() *schema.Resource {
@ -175,15 +175,28 @@ func dataSourceAlicloudImagesRead(d *schema.ResourceData, meta interface{}) erro
params.ImageOwnerAlias = ecs.ImageOwnerAlias(owners.(string)) params.ImageOwnerAlias = ecs.ImageOwnerAlias(owners.(string))
} }
resp, _, err := conn.DescribeImages(params) var allImages []ecs.ImageType
if err != nil {
return err 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 var filteredImages []ecs.ImageType
if nameRegexOk { if nameRegexOk {
r := regexp.MustCompile(nameRegex.(string)) 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 // Check for a very rare case where the response would include no
// image name. No name means nothing to attempt a match against, // image name. No name means nothing to attempt a match against,
// therefore we are skipping such image. // therefore we are skipping such image.
@ -198,7 +211,7 @@ func dataSourceAlicloudImagesRead(d *schema.ResourceData, meta interface{}) erro
} }
} }
} else { } else {
filteredImages = resp[:] filteredImages = allImages[:]
} }
var images []ecs.ImageType var images []ecs.ImageType

View File

@ -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_14")),
),
},
},
})
}
// Instance store test - using centos images // Instance store test - using centos images
const testAccCheckAlicloudImagesDataSourceImagesConfig = ` const testAccCheckAlicloudImagesDataSourceImagesConfig = `
data "alicloud_images" "multi_image" { 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}.*" 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_14.*_64"
}
`

View File

@ -17,8 +17,6 @@ func TestAccAlicloudInstanceTypesDataSource_basic(t *testing.T) {
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAlicloudDataSourceID("data.alicloud_instance_types.4c8g"), 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.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.memory_size", "8"),
resource.TestCheckResourceAttr("data.alicloud_instance_types.4c8g", "instance_types.0.id", "ecs.s3.large"), resource.TestCheckResourceAttr("data.alicloud_instance_types.4c8g", "instance_types.0.id", "ecs.s3.large"),

View File

@ -71,11 +71,6 @@ func TestAccAlicloudRegionsDataSource_empty(t *testing.T) {
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAlicloudDataSourceID("data.alicloud_regions.empty_params_region"), 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"), resource.TestCheckResourceAttr("data.alicloud_regions.empty_params_region", "regions.0.id", "cn-shenzhen"),
resource.TestCheckResourceAttr("data.alicloud_regions.empty_params_region", "regions.0.region_id", "cn-shenzhen"), resource.TestCheckResourceAttr("data.alicloud_regions.empty_params_region", "regions.0.region_id", "cn-shenzhen"),
resource.TestCheckResourceAttr("data.alicloud_regions.empty_params_region", "regions.0.local_name", "华南 1"), resource.TestCheckResourceAttr("data.alicloud_regions.empty_params_region", "regions.0.local_name", "华南 1"),

View File

@ -1,7 +1,10 @@
package alicloud package alicloud
import ( import (
"fmt"
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"strconv"
"testing" "testing"
) )
@ -23,6 +26,7 @@ func TestAccAlicloudZonesDataSource_basic(t *testing.T) {
} }
func TestAccAlicloudZonesDataSource_filter(t *testing.T) { func TestAccAlicloudZonesDataSource_filter(t *testing.T) {
resource.Test(t, resource.TestCase{ resource.Test(t, resource.TestCase{
PreCheck: func() { PreCheck: func() {
testAccPreCheck(t) testAccPreCheck(t)
@ -33,7 +37,7 @@ func TestAccAlicloudZonesDataSource_filter(t *testing.T) {
Config: testAccCheckAlicloudZonesDataSourceFilter, Config: testAccCheckAlicloudZonesDataSourceFilter,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAlicloudDataSourceID("data.alicloud_zones.foo"), testAccCheckAlicloudDataSourceID("data.alicloud_zones.foo"),
resource.TestCheckResourceAttr("data.alicloud_zones.foo", "zones.#", "2"), testCheckZoneLength("data.alicloud_zones.foo"),
), ),
}, },
@ -41,13 +45,59 @@ func TestAccAlicloudZonesDataSource_filter(t *testing.T) {
Config: testAccCheckAlicloudZonesDataSourceFilterIoOptimized, Config: testAccCheckAlicloudZonesDataSourceFilterIoOptimized,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckAlicloudDataSourceID("data.alicloud_zones.foo"), testAccCheckAlicloudDataSourceID("data.alicloud_zones.foo"),
resource.TestCheckResourceAttr("data.alicloud_zones.foo", "zones.#", "1"), testCheckZoneLength("data.alicloud_zones.foo"),
), ),
}, },
}, },
}) })
} }
func TestAccAlicloudZonesDataSource_unitRegion(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCheckAlicloudZonesDataSource_unitRegion,
Check: resource.ComposeTestCheckFunc(
testAccCheckAlicloudDataSourceID("data.alicloud_zones.foo"),
),
},
},
})
}
// the zone length changed occasionally
// check by range to avoid test case failure
func testCheckZoneLength(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
}
}
const testAccCheckAlicloudZonesDataSourceBasicConfig = ` const testAccCheckAlicloudZonesDataSourceBasicConfig = `
data "alicloud_zones" "foo" { data "alicloud_zones" "foo" {
} }
@ -55,16 +105,28 @@ data "alicloud_zones" "foo" {
const testAccCheckAlicloudZonesDataSourceFilter = ` const testAccCheckAlicloudZonesDataSourceFilter = `
data "alicloud_zones" "foo" { data "alicloud_zones" "foo" {
"available_instance_type"= "ecs.c2.xlarge" available_instance_type= "ecs.c2.xlarge"
"available_resource_creation"= "VSwitch" available_resource_creation= "VSwitch"
"available_disk_category"= "cloud_efficiency" available_disk_category= "cloud_efficiency"
} }
` `
const testAccCheckAlicloudZonesDataSourceFilterIoOptimized = ` const testAccCheckAlicloudZonesDataSourceFilterIoOptimized = `
data "alicloud_zones" "foo" { data "alicloud_zones" "foo" {
"available_instance_type"= "ecs.c2.xlarge" available_instance_type= "ecs.c2.xlarge"
"available_resource_creation"= "IoOptimized" available_resource_creation= "IoOptimized"
"available_disk_category"= "cloud" available_disk_category= "cloud"
}
`
const testAccCheckAlicloudZonesDataSource_unitRegion = `
provider "alicloud" {
alias = "northeast"
region = "ap-northeast-1"
}
data "alicloud_zones" "foo" {
provider = "alicloud.northeast"
available_resource_creation= "VSwitch"
} }
` `

View File

@ -9,6 +9,7 @@ const (
DiskIncorrectStatus = "IncorrectDiskStatus" DiskIncorrectStatus = "IncorrectDiskStatus"
DiskCreatingSnapshot = "DiskCreatingSnapshot" DiskCreatingSnapshot = "DiskCreatingSnapshot"
InstanceLockedForSecurity = "InstanceLockedForSecurity" InstanceLockedForSecurity = "InstanceLockedForSecurity"
SystemDiskNotFound = "SystemDiskNotFound"
// eip // eip
EipIncorrectStatus = "IncorrectEipStatus" EipIncorrectStatus = "IncorrectEipStatus"
InstanceIncorrectStatus = "IncorrectInstanceStatus" InstanceIncorrectStatus = "IncorrectInstanceStatus"

View File

@ -30,3 +30,8 @@ const (
GroupRulePolicyAccept = GroupRulePolicy("accept") GroupRulePolicyAccept = GroupRulePolicy("accept")
GroupRulePolicyDrop = GroupRulePolicy("drop") GroupRulePolicyDrop = GroupRulePolicy("drop")
) )
const (
EcsApiVersion20160314 = "2016-03-14"
EcsApiVersion20140526 = "2014-05-26"
)

View File

@ -8,13 +8,41 @@ import (
) )
type Listener struct { type Listener struct {
slb.HTTPListenerType
InstancePort int InstancePort int
LoadBalancerPort int LoadBalancerPort int
Protocol string Protocol string
//tcp & udp
PersistenceTimeout int
//https
SSLCertificateId string SSLCertificateId string
Bandwidth int
//tcp
HealthCheckType slb.HealthCheckType
//api interface: http & https is HealthCheckTimeout, tcp & udp is HealthCheckConnectTimeout
HealthCheckConnectTimeout int
} }
type ListenerErr struct {
ErrType string
Err error
}
func (e *ListenerErr) Error() string {
return e.ErrType + " " + e.Err.Error()
}
const (
HealthCheckErrType = "healthCheckErrType"
StickySessionErrType = "stickySessionErrType"
CookieTimeOutErrType = "cookieTimeoutErrType"
CookieErrType = "cookieErrType"
)
// Takes the result of flatmap.Expand for an array of listeners and // Takes the result of flatmap.Expand for an array of listeners and
// returns ELB API compatible objects // returns ELB API compatible objects
func expandListeners(configured []interface{}) ([]*Listener, error) { func expandListeners(configured []interface{}) ([]*Listener, error) {
@ -31,13 +59,78 @@ func expandListeners(configured []interface{}) ([]*Listener, error) {
InstancePort: ip, InstancePort: ip,
LoadBalancerPort: lp, LoadBalancerPort: lp,
Protocol: data["lb_protocol"].(string), Protocol: data["lb_protocol"].(string),
Bandwidth: data["bandwidth"].(int), }
l.Bandwidth = data["bandwidth"].(int)
if v, ok := data["scheduler"]; ok {
l.Scheduler = slb.SchedulerType(v.(string))
} }
if v, ok := data["ssl_certificate_id"]; ok { if v, ok := data["ssl_certificate_id"]; ok {
l.SSLCertificateId = v.(string) l.SSLCertificateId = v.(string)
} }
if v, ok := data["sticky_session"]; ok {
l.StickySession = slb.FlagType(v.(string))
}
if v, ok := data["sticky_session_type"]; ok {
l.StickySessionType = slb.StickySessionType(v.(string))
}
if v, ok := data["cookie_timeout"]; ok {
l.CookieTimeout = v.(int)
}
if v, ok := data["cookie"]; ok {
l.Cookie = v.(string)
}
if v, ok := data["persistence_timeout"]; ok {
l.PersistenceTimeout = v.(int)
}
if v, ok := data["health_check"]; ok {
l.HealthCheck = slb.FlagType(v.(string))
}
if v, ok := data["health_check_type"]; ok {
l.HealthCheckType = slb.HealthCheckType(v.(string))
}
if v, ok := data["health_check_domain"]; ok {
l.HealthCheckDomain = v.(string)
}
if v, ok := data["health_check_uri"]; ok {
l.HealthCheckURI = v.(string)
}
if v, ok := data["health_check_connect_port"]; ok {
l.HealthCheckConnectPort = v.(int)
}
if v, ok := data["healthy_threshold"]; ok {
l.HealthyThreshold = v.(int)
}
if v, ok := data["unhealthy_threshold"]; ok {
l.UnhealthyThreshold = v.(int)
}
if v, ok := data["health_check_timeout"]; ok {
l.HealthCheckTimeout = v.(int)
}
if v, ok := data["health_check_interval"]; ok {
l.HealthCheckInterval = v.(int)
}
if v, ok := data["health_check_http_code"]; ok {
l.HealthCheckHttpCode = slb.HealthCheckHttpCodeType(v.(string))
}
var valid bool var valid bool
if l.SSLCertificateId != "" { if l.SSLCertificateId != "" {
// validate the protocol is correct // validate the protocol is correct

View File

@ -26,7 +26,7 @@ func Provider() terraform.ResourceProvider {
"region": &schema.Schema{ "region": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_REGION", "cn-beijing"), DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_REGION", DEFAULT_REGION),
Description: descriptions["region"], Description: descriptions["region"],
}, },
}, },
@ -43,6 +43,7 @@ func Provider() terraform.ResourceProvider {
"alicloud_disk_attachment": resourceAliyunDiskAttachment(), "alicloud_disk_attachment": resourceAliyunDiskAttachment(),
"alicloud_security_group": resourceAliyunSecurityGroup(), "alicloud_security_group": resourceAliyunSecurityGroup(),
"alicloud_security_group_rule": resourceAliyunSecurityGroupRule(), "alicloud_security_group_rule": resourceAliyunSecurityGroupRule(),
"alicloud_db_instance": resourceAlicloudDBInstance(),
"alicloud_vpc": resourceAliyunVpc(), "alicloud_vpc": resourceAliyunVpc(),
"alicloud_nat_gateway": resourceAliyunNatGateway(), "alicloud_nat_gateway": resourceAliyunNatGateway(),
//both subnet and vswith exists,cause compatible old version, and compatible aws habit. //both subnet and vswith exists,cause compatible old version, and compatible aws habit.

View File

@ -0,0 +1,545 @@
package alicloud
import (
"bytes"
"encoding/json"
"fmt"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/rds"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"log"
"strconv"
"strings"
"time"
)
func resourceAlicloudDBInstance() *schema.Resource {
return &schema.Resource{
Create: resourceAlicloudDBInstanceCreate,
Read: resourceAlicloudDBInstanceRead,
Update: resourceAlicloudDBInstanceUpdate,
Delete: resourceAlicloudDBInstanceDelete,
Schema: map[string]*schema.Schema{
"engine": &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateAllowedStringValue([]string{"MySQL", "SQLServer", "PostgreSQL", "PPAS"}),
ForceNew: true,
Required: true,
},
"engine_version": &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateAllowedStringValue([]string{"5.5", "5.6", "5.7", "2008r2", "2012", "9.4", "9.3"}),
ForceNew: true,
Required: true,
},
"db_instance_class": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"db_instance_storage": &schema.Schema{
Type: schema.TypeInt,
Required: true,
},
"instance_charge_type": &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateAllowedStringValue([]string{string(rds.Postpaid), string(rds.Prepaid)}),
Optional: true,
ForceNew: true,
Default: rds.Postpaid,
},
"period": &schema.Schema{
Type: schema.TypeInt,
ValidateFunc: validateAllowedIntValue([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 24, 36}),
Optional: true,
ForceNew: true,
Default: 1,
},
"zone_id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"multi_az": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
},
"db_instance_net_type": &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateAllowedStringValue([]string{string(common.Internet), string(common.Intranet)}),
Optional: true,
},
"allocate_public_connection": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"instance_network_type": &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateAllowedStringValue([]string{string(common.VPC), string(common.Classic)}),
Optional: true,
Computed: true,
},
"vswitch_id": &schema.Schema{
Type: schema.TypeString,
ForceNew: true,
Optional: true,
},
"master_user_name": &schema.Schema{
Type: schema.TypeString,
ForceNew: true,
Optional: true,
},
"master_user_password": &schema.Schema{
Type: schema.TypeString,
ForceNew: true,
Optional: true,
Sensitive: true,
},
"preferred_backup_period": &schema.Schema{
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
// terraform does not support ValidateFunc of TypeList attr
// ValidateFunc: validateAllowedStringValue([]string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}),
Optional: true,
},
"preferred_backup_time": &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateAllowedStringValue(rds.BACKUP_TIME),
Optional: true,
},
"backup_retention_period": &schema.Schema{
Type: schema.TypeInt,
ValidateFunc: validateIntegerInRange(7, 730),
Optional: true,
},
"security_ips": &schema.Schema{
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
Computed: true,
Optional: true,
},
"port": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"connections": &schema.Schema{
Type: schema.TypeList,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"connection_string": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"ip_type": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"ip_address": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
},
},
Computed: true,
},
"db_mappings": &schema.Schema{
Type: schema.TypeSet,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"db_name": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"character_set_name": &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateAllowedStringValue(rds.CHARACTER_SET_NAME),
Required: true,
},
"db_description": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
},
},
Optional: true,
Set: resourceAlicloudDatabaseHash,
},
},
}
}
func resourceAlicloudDatabaseHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["db_name"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["character_set_name"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["db_description"].(string)))
return hashcode.String(buf.String())
}
func resourceAlicloudDBInstanceCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*AliyunClient)
conn := client.rdsconn
args, err := buildDBCreateOrderArgs(d, meta)
if err != nil {
return err
}
resp, err := conn.CreateOrder(args)
if err != nil {
return fmt.Errorf("Error creating Alicloud db instance: %#v", err)
}
instanceId := resp.DBInstanceId
if instanceId == "" {
return fmt.Errorf("Error get Alicloud db instance id")
}
d.SetId(instanceId)
d.Set("instance_charge_type", d.Get("instance_charge_type"))
d.Set("period", d.Get("period"))
d.Set("period_type", d.Get("period_type"))
// 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)
}
if err := modifySecurityIps(d.Id(), d.Get("security_ips"), meta); err != nil {
return err
}
masterUserName := d.Get("master_user_name").(string)
masterUserPwd := d.Get("master_user_password").(string)
if masterUserName != "" && masterUserPwd != "" {
if err := client.CreateAccountByInfo(d.Id(), masterUserName, masterUserPwd); err != nil {
return fmt.Errorf("Create db account %s error: %v", masterUserName, err)
}
}
if d.Get("allocate_public_connection").(bool) {
if err := client.AllocateDBPublicConnection(d.Id(), DB_DEFAULT_CONNECT_PORT); err != nil {
return fmt.Errorf("Allocate public connection error: %v", err)
}
}
return resourceAlicloudDBInstanceUpdate(d, meta)
}
func modifySecurityIps(id string, ips interface{}, meta interface{}) error {
client := meta.(*AliyunClient)
ipList := expandStringList(ips.([]interface{}))
ipstr := strings.Join(ipList[:], COMMA_SEPARATED)
// default disable connect from outside
if ipstr == "" {
ipstr = LOCAL_HOST_IP
}
if err := client.ModifyDBSecurityIps(id, ipstr); err != nil {
return fmt.Errorf("Error modify security ips %s: %#v", ipstr, err)
}
return nil
}
func resourceAlicloudDBInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*AliyunClient)
conn := client.rdsconn
d.Partial(true)
if d.HasChange("db_mappings") {
o, n := d.GetChange("db_mappings")
os := o.(*schema.Set)
ns := n.(*schema.Set)
var allDbs []string
remove := os.Difference(ns).List()
add := ns.Difference(os).List()
if len(remove) > 0 && len(add) > 0 {
return fmt.Errorf("Failure modify database, we neither support create and delete database simultaneous nor modify database attributes.")
}
if len(remove) > 0 {
for _, db := range remove {
dbm, _ := db.(map[string]interface{})
if err := conn.DeleteDatabase(d.Id(), dbm["db_name"].(string)); err != nil {
return fmt.Errorf("Failure delete database %s: %#v", dbm["db_name"].(string), err)
}
}
}
if len(add) > 0 {
for _, db := range add {
dbm, _ := db.(map[string]interface{})
dbName := dbm["db_name"].(string)
allDbs = append(allDbs, dbName)
if err := client.CreateDatabaseByInfo(d.Id(), dbName, dbm["character_set_name"].(string), dbm["db_description"].(string)); err != nil {
return fmt.Errorf("Failure create database %s: %#v", dbName, err)
}
}
}
if err := conn.WaitForAllDatabase(d.Id(), allDbs, rds.Running, 600); err != nil {
return fmt.Errorf("Failure create database %#v", err)
}
if user := d.Get("master_user_name").(string); user != "" {
for _, dbName := range allDbs {
if err := client.GrantDBPrivilege2Account(d.Id(), user, dbName); err != nil {
return fmt.Errorf("Failed to grant database %s readwrite privilege to account %s: %#v", dbName, user, err)
}
}
}
d.SetPartial("db_mappings")
}
if d.HasChange("preferred_backup_period") || d.HasChange("preferred_backup_time") || d.HasChange("backup_retention_period") {
period := d.Get("preferred_backup_period").([]interface{})
periodList := expandStringList(period)
time := d.Get("preferred_backup_time").(string)
retention := d.Get("backup_retention_period").(int)
if time == "" || retention == 0 || len(periodList) < 1 {
return fmt.Errorf("Both backup_time, backup_period and retention_period are required to set backup policy.")
}
ps := strings.Join(periodList[:], COMMA_SEPARATED)
if err := client.ConfigDBBackup(d.Id(), time, ps, retention); err != nil {
return fmt.Errorf("Error set backup policy: %#v", err)
}
d.SetPartial("preferred_backup_period")
d.SetPartial("preferred_backup_time")
d.SetPartial("backup_retention_period")
}
if d.HasChange("security_ips") {
if err := modifySecurityIps(d.Id(), d.Get("security_ips"), meta); err != nil {
return err
}
d.SetPartial("security_ips")
}
if d.HasChange("db_instance_class") || d.HasChange("db_instance_storage") {
co, cn := d.GetChange("db_instance_class")
so, sn := d.GetChange("db_instance_storage")
classOld := co.(string)
classNew := cn.(string)
storageOld := so.(int)
storageNew := sn.(int)
// update except the first time, because we will do it in create function
if classOld != "" && storageOld != 0 {
chargeType := d.Get("instance_charge_type").(string)
if chargeType == string(rds.Prepaid) {
return fmt.Errorf("Prepaid db instance does not support modify db_instance_class or db_instance_storage")
}
if err := client.ModifyDBClassStorage(d.Id(), classNew, strconv.Itoa(storageNew)); err != nil {
return fmt.Errorf("Error modify db instance class or storage error: %#v", err)
}
}
}
d.Partial(false)
return resourceAlicloudDBInstanceRead(d, meta)
}
func resourceAlicloudDBInstanceRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*AliyunClient)
conn := client.rdsconn
instance, err := client.DescribeDBInstanceById(d.Id())
if err != nil {
if notFoundError(err) {
d.SetId("")
return nil
}
return fmt.Errorf("Error Describe DB InstanceAttribute: %#v", err)
}
args := rds.DescribeDatabasesArgs{
DBInstanceId: d.Id(),
}
resp, err := conn.DescribeDatabases(&args)
if err != nil {
return err
}
d.Set("db_mappings", flattenDatabaseMappings(resp.Databases.Database))
argn := rds.DescribeDBInstanceNetInfoArgs{
DBInstanceId: d.Id(),
}
resn, err := conn.DescribeDBInstanceNetInfo(&argn)
if err != nil {
return err
}
d.Set("connections", flattenDBConnections(resn.DBInstanceNetInfos.DBInstanceNetInfo))
ips, err := client.GetSecurityIps(d.Id())
if err != nil {
log.Printf("Describe DB security ips error: %#v", err)
}
d.Set("security_ips", ips)
d.Set("engine", instance.Engine)
d.Set("engine_version", instance.EngineVersion)
d.Set("db_instance_class", instance.DBInstanceClass)
d.Set("port", instance.Port)
d.Set("db_instance_storage", instance.DBInstanceStorage)
d.Set("zone_id", instance.ZoneId)
d.Set("db_instance_net_type", instance.DBInstanceNetType)
d.Set("instance_network_type", instance.InstanceNetworkType)
return nil
}
func resourceAlicloudDBInstanceDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AliyunClient).rdsconn
return resource.Retry(5*time.Minute, func() *resource.RetryError {
err := conn.DeleteInstance(d.Id())
if err != nil {
return resource.RetryableError(fmt.Errorf("DB Instance in use - trying again while it is deleted."))
}
args := &rds.DescribeDBInstancesArgs{
DBInstanceId: d.Id(),
}
resp, err := conn.DescribeDBInstanceAttribute(args)
if err != nil {
return resource.NonRetryableError(err)
} else if len(resp.Items.DBInstanceAttribute) < 1 {
return nil
}
return resource.RetryableError(fmt.Errorf("DB in use - trying again while it is deleted."))
})
}
func buildDBCreateOrderArgs(d *schema.ResourceData, meta interface{}) (*rds.CreateOrderArgs, error) {
client := meta.(*AliyunClient)
args := &rds.CreateOrderArgs{
RegionId: getRegion(d, meta),
// we does not expose this param to user,
// because create prepaid instance progress will be stopped when set auto_pay to false,
// then could not get instance info, cause timeout error
AutoPay: "true",
EngineVersion: d.Get("engine_version").(string),
Engine: rds.Engine(d.Get("engine").(string)),
DBInstanceStorage: d.Get("db_instance_storage").(int),
DBInstanceClass: d.Get("db_instance_class").(string),
Quantity: DEFAULT_INSTANCE_COUNT,
Resource: rds.DefaultResource,
}
bussStr, err := json.Marshal(DefaultBusinessInfo)
if err != nil {
return nil, fmt.Errorf("Failed to translate bussiness info %#v from json to string", DefaultBusinessInfo)
}
args.BusinessInfo = string(bussStr)
zoneId := d.Get("zone_id").(string)
args.ZoneId = zoneId
multiAZ := d.Get("multi_az").(bool)
if multiAZ {
if zoneId != "" {
return nil, fmt.Errorf("You cannot set the ZoneId parameter when the MultiAZ parameter is set to true")
}
izs, err := client.DescribeMultiIZByRegion()
if err != nil {
return nil, fmt.Errorf("Get multiAZ id error")
}
if len(izs) < 1 {
return nil, fmt.Errorf("Current region does not support MultiAZ.")
}
args.ZoneId = izs[0]
}
vswitchId := d.Get("vswitch_id").(string)
networkType := d.Get("instance_network_type").(string)
args.InstanceNetworkType = common.NetworkType(networkType)
if vswitchId != "" {
args.VSwitchId = vswitchId
// check InstanceNetworkType with vswitchId
if networkType == string(common.Classic) {
return nil, fmt.Errorf("When fill vswitchId, you shold set instance_network_type to VPC")
} else if networkType == "" {
args.InstanceNetworkType = common.VPC
}
// get vpcId
vpcId, err := client.GetVpcIdByVSwitchId(vswitchId)
if err != nil {
return nil, fmt.Errorf("VswitchId %s is not valid of current region", vswitchId)
}
// fill vpcId by vswitchId
args.VPCId = vpcId
// check vswitchId in zone
vsw, err := client.QueryVswitchById(vpcId, vswitchId)
if err != nil {
return nil, fmt.Errorf("VswitchId %s is not valid of current region", vswitchId)
}
if zoneId == "" {
args.ZoneId = vsw.ZoneId
} else if vsw.ZoneId != zoneId {
return nil, fmt.Errorf("VswitchId %s is not belong to the zone %s", vswitchId, zoneId)
}
}
if v := d.Get("db_instance_net_type").(string); v != "" {
args.DBInstanceNetType = common.NetType(v)
}
chargeType := d.Get("instance_charge_type").(string)
if chargeType != "" {
args.PayType = rds.DBPayType(chargeType)
} else {
args.PayType = rds.Postpaid
}
// if charge type is postpaid, the commodity code must set to bards
if chargeType == string(rds.Postpaid) {
args.CommodityCode = rds.Bards
} else {
args.CommodityCode = rds.Rds
}
period := d.Get("period").(int)
args.UsedTime, args.TimeType = TransformPeriod2Time(period, chargeType)
return args, nil
}

View File

@ -0,0 +1,765 @@
package alicloud
import (
"fmt"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/rds"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"log"
"strings"
"testing"
)
func TestAccAlicloudDBInstance_basic(t *testing.T) {
var instance rds.DBInstanceAttribute
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
// module name
IDRefreshName: "alicloud_db_instance.foo",
Providers: testAccProviders,
CheckDestroy: testAccCheckDBInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBInstanceConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckDBInstanceExists(
"alicloud_db_instance.foo", &instance),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"port",
"3306"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"db_instance_storage",
"10"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"instance_network_type",
"Classic"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"db_instance_net_type",
"Intranet"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"engine_version",
"5.6"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"engine",
"MySQL"),
),
},
},
})
}
func TestAccAlicloudDBInstance_vpc(t *testing.T) {
var instance rds.DBInstanceAttribute
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
// module name
IDRefreshName: "alicloud_db_instance.foo",
Providers: testAccProviders,
CheckDestroy: testAccCheckDBInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBInstance_vpc,
Check: resource.ComposeTestCheckFunc(
testAccCheckDBInstanceExists(
"alicloud_db_instance.foo", &instance),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"port",
"3306"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"db_instance_storage",
"10"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"instance_network_type",
"VPC"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"db_instance_net_type",
"Intranet"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"engine_version",
"5.6"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"engine",
"MySQL"),
),
},
},
})
}
func TestC2CAlicloudDBInstance_prepaid_order(t *testing.T) {
var instance rds.DBInstanceAttribute
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
// module name
IDRefreshName: "alicloud_db_instance.foo",
Providers: testAccProviders,
CheckDestroy: testAccCheckDBInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBInstance_prepaid_order,
Check: resource.ComposeTestCheckFunc(
testAccCheckDBInstanceExists(
"alicloud_db_instance.foo", &instance),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"port",
"3306"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"db_instance_storage",
"10"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"instance_network_type",
"VPC"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"db_instance_net_type",
"Intranet"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"engine_version",
"5.6"),
resource.TestCheckResourceAttr(
"alicloud_db_instance.foo",
"engine",
"MySQL"),
),
},
},
})
}
func TestAccAlicloudDBInstance_multiIZ(t *testing.T) {
var instance rds.DBInstanceAttribute
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
// module name
IDRefreshName: "alicloud_db_instance.foo",
Providers: testAccProviders,
CheckDestroy: testAccCheckDBInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBInstance_multiIZ,
Check: resource.ComposeTestCheckFunc(
testAccCheckDBInstanceExists(
"alicloud_db_instance.foo", &instance),
testAccCheckDBInstanceMultiIZ(&instance),
),
},
},
})
}
func TestAccAlicloudDBInstance_database(t *testing.T) {
var instance rds.DBInstanceAttribute
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
// module name
IDRefreshName: "alicloud_db_instance.foo",
Providers: testAccProviders,
CheckDestroy: testAccCheckDBInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBInstance_database,
Check: resource.ComposeTestCheckFunc(
testAccCheckDBInstanceExists(
"alicloud_db_instance.foo", &instance),
resource.TestCheckResourceAttr("alicloud_db_instance.foo", "db_mappings.#", "2"),
),
},
resource.TestStep{
Config: testAccDBInstance_database_update,
Check: resource.ComposeTestCheckFunc(
testAccCheckDBInstanceExists(
"alicloud_db_instance.foo", &instance),
resource.TestCheckResourceAttr("alicloud_db_instance.foo", "db_mappings.#", "3"),
),
},
},
})
}
func TestAccAlicloudDBInstance_account(t *testing.T) {
var instance rds.DBInstanceAttribute
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
// module name
IDRefreshName: "alicloud_db_instance.foo",
Providers: testAccProviders,
CheckDestroy: testAccCheckDBInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBInstance_grantDatabasePrivilege2Account,
Check: resource.ComposeTestCheckFunc(
testAccCheckDBInstanceExists(
"alicloud_db_instance.foo", &instance),
resource.TestCheckResourceAttr("alicloud_db_instance.foo", "db_mappings.#", "2"),
testAccCheckAccountHasPrivilege2Database("alicloud_db_instance.foo", "tester", "foo", "ReadWrite"),
),
},
},
})
}
func TestAccAlicloudDBInstance_allocatePublicConnection(t *testing.T) {
var instance rds.DBInstanceAttribute
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
// module name
IDRefreshName: "alicloud_db_instance.foo",
Providers: testAccProviders,
CheckDestroy: testAccCheckDBInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBInstance_allocatePublicConnection,
Check: resource.ComposeTestCheckFunc(
testAccCheckDBInstanceExists(
"alicloud_db_instance.foo", &instance),
resource.TestCheckResourceAttr("alicloud_db_instance.foo", "connections.#", "2"),
testAccCheckHasPublicConnection("alicloud_db_instance.foo"),
),
},
},
})
}
func TestAccAlicloudDBInstance_backupPolicy(t *testing.T) {
var policies []map[string]interface{}
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
// module name
IDRefreshName: "alicloud_db_instance.foo",
Providers: testAccProviders,
CheckDestroy: testAccCheckDBInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBInstance_backup,
Check: resource.ComposeTestCheckFunc(
testAccCheckBackupPolicyExists(
"alicloud_db_instance.foo", policies),
testAccCheckKeyValueInMaps(policies, "backup policy", "preferred_backup_period", "Wednesday,Thursday"),
testAccCheckKeyValueInMaps(policies, "backup policy", "preferred_backup_time", "00:00Z-01:00Z"),
),
},
},
})
}
func TestAccAlicloudDBInstance_securityIps(t *testing.T) {
var ips []map[string]interface{}
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
// module name
IDRefreshName: "alicloud_db_instance.foo",
Providers: testAccProviders,
CheckDestroy: testAccCheckDBInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBInstance_securityIps,
Check: resource.ComposeTestCheckFunc(
testAccCheckSecurityIpExists(
"alicloud_db_instance.foo", ips),
testAccCheckKeyValueInMaps(ips, "security ip", "security_ips", "127.0.0.1"),
),
},
resource.TestStep{
Config: testAccDBInstance_securityIpsConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckSecurityIpExists(
"alicloud_db_instance.foo", ips),
testAccCheckKeyValueInMaps(ips, "security ip", "security_ips", "10.168.1.12,100.69.7.112"),
),
},
},
})
}
func TestAccAlicloudDBInstance_upgradeClass(t *testing.T) {
var instance rds.DBInstanceAttribute
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
// module name
IDRefreshName: "alicloud_db_instance.foo",
Providers: testAccProviders,
CheckDestroy: testAccCheckDBInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDBInstance_class,
Check: resource.ComposeTestCheckFunc(
testAccCheckDBInstanceExists(
"alicloud_db_instance.foo", &instance),
resource.TestCheckResourceAttr("alicloud_db_instance.foo", "db_instance_class", "rds.mysql.t1.small"),
),
},
resource.TestStep{
Config: testAccDBInstance_classUpgrade,
Check: resource.ComposeTestCheckFunc(
testAccCheckDBInstanceExists(
"alicloud_db_instance.foo", &instance),
resource.TestCheckResourceAttr("alicloud_db_instance.foo", "db_instance_class", "rds.mysql.s1.small"),
),
},
},
})
}
func testAccCheckSecurityIpExists(n string, ips []map[string]interface{}) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No DB Instance ID is set")
}
conn := testAccProvider.Meta().(*AliyunClient).rdsconn
args := rds.DescribeDBInstanceIPsArgs{
DBInstanceId: rs.Primary.ID,
}
resp, err := conn.DescribeDBInstanceIPs(&args)
log.Printf("[DEBUG] check instance %s security ip %#v", rs.Primary.ID, resp)
if err != nil {
return err
}
p := resp.Items.DBInstanceIPArray
if len(p) < 1 {
return fmt.Errorf("DB security ip not found")
}
ips = flattenDBSecurityIPs(p)
return nil
}
}
func testAccCheckDBInstanceMultiIZ(i *rds.DBInstanceAttribute) resource.TestCheckFunc {
return func(s *terraform.State) error {
if !strings.Contains(i.ZoneId, MULTI_IZ_SYMBOL) {
return fmt.Errorf("Current region does not support multiIZ.")
}
return nil
}
}
func testAccCheckAccountHasPrivilege2Database(n, accountName, dbName, privilege string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No DB instance ID is set")
}
conn := testAccProvider.Meta().(*AliyunClient).rdsconn
if err := conn.WaitForAccountPrivilege(rs.Primary.ID, accountName, dbName, rds.AccountPrivilege(privilege), 50); err != nil {
return fmt.Errorf("Failed to grant database %s privilege to account %s: %v", dbName, accountName, err)
}
return nil
}
}
func testAccCheckHasPublicConnection(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No DB instance ID is set")
}
conn := testAccProvider.Meta().(*AliyunClient).rdsconn
if err := conn.WaitForPublicConnection(rs.Primary.ID, 50); err != nil {
return fmt.Errorf("Failed to allocate public connection: %v", err)
}
return nil
}
}
func testAccCheckDBInstanceExists(n string, d *rds.DBInstanceAttribute) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No DB Instance ID is set")
}
client := testAccProvider.Meta().(*AliyunClient)
attr, err := client.DescribeDBInstanceById(rs.Primary.ID)
log.Printf("[DEBUG] check instance %s attribute %#v", rs.Primary.ID, attr)
if err != nil {
return err
}
if attr == nil {
return fmt.Errorf("DB Instance not found")
}
*d = *attr
return nil
}
}
func testAccCheckBackupPolicyExists(n string, ps []map[string]interface{}) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Backup policy not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No DB Instance ID is set")
}
conn := testAccProvider.Meta().(*AliyunClient).rdsconn
args := rds.DescribeBackupPolicyArgs{
DBInstanceId: rs.Primary.ID,
}
resp, err := conn.DescribeBackupPolicy(&args)
log.Printf("[DEBUG] check instance %s backup policy %#v", rs.Primary.ID, resp)
if err != nil {
return err
}
var bs []rds.BackupPolicy
bs = append(bs, resp.BackupPolicy)
ps = flattenDBBackup(bs)
return nil
}
}
func testAccCheckKeyValueInMaps(ps []map[string]interface{}, propName, key, value string) resource.TestCheckFunc {
return func(s *terraform.State) error {
for _, policy := range ps {
if policy[key].(string) != value {
return fmt.Errorf("DB %s attribute '%s' expected %#v, got %#v", propName, key, value, policy[key])
}
}
return nil
}
}
func testAccCheckDBInstanceDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*AliyunClient)
for _, rs := range s.RootModule().Resources {
if rs.Type != "alicloud_db_instance.foo" {
continue
}
ins, err := client.DescribeDBInstanceById(rs.Primary.ID)
if ins != nil {
return fmt.Errorf("Error DB Instance 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 testAccDBInstanceConfig = `
resource "alicloud_db_instance" "foo" {
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.t1.small"
db_instance_storage = "10"
instance_charge_type = "Postpaid"
db_instance_net_type = "Intranet"
}
`
const testAccDBInstance_vpc = `
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_db_instance" "foo" {
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.t1.small"
db_instance_storage = "10"
instance_charge_type = "Postpaid"
db_instance_net_type = "Intranet"
vswitch_id = "${alicloud_vswitch.foo.id}"
}
`
const testAccDBInstance_multiIZ = `
resource "alicloud_db_instance" "foo" {
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.t1.small"
db_instance_storage = "10"
db_instance_net_type = "Intranet"
multi_az = true
}
`
const testAccDBInstance_prepaid_order = `
resource "alicloud_db_instance" "foo" {
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.t1.small"
db_instance_storage = "10"
instance_charge_type = "Prepaid"
db_instance_net_type = "Intranet"
}
`
const testAccDBInstance_database = `
resource "alicloud_db_instance" "foo" {
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.t1.small"
db_instance_storage = "10"
instance_charge_type = "Postpaid"
db_instance_net_type = "Intranet"
db_mappings = [
{
"db_name" = "foo"
"character_set_name" = "utf8"
"db_description" = "tf"
},{
"db_name" = "bar"
"character_set_name" = "utf8"
"db_description" = "tf"
}]
}
`
const testAccDBInstance_database_update = `
resource "alicloud_db_instance" "foo" {
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.t1.small"
db_instance_storage = "10"
instance_charge_type = "Postpaid"
db_instance_net_type = "Intranet"
db_mappings = [
{
"db_name" = "foo"
"character_set_name" = "utf8"
"db_description" = "tf"
},{
"db_name" = "bar"
"character_set_name" = "utf8"
"db_description" = "tf"
},{
"db_name" = "zzz"
"character_set_name" = "utf8"
"db_description" = "tf"
}]
}
`
const testAccDBInstance_grantDatabasePrivilege2Account = `
resource "alicloud_db_instance" "foo" {
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.t1.small"
db_instance_storage = "10"
instance_charge_type = "Postpaid"
db_instance_net_type = "Intranet"
master_user_name = "tester"
master_user_password = "Test12345"
db_mappings = [
{
"db_name" = "foo"
"character_set_name" = "utf8"
"db_description" = "tf"
},{
"db_name" = "bar"
"character_set_name" = "utf8"
"db_description" = "tf"
}]
}
`
const testAccDBInstance_allocatePublicConnection = `
resource "alicloud_db_instance" "foo" {
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.t1.small"
db_instance_storage = "10"
instance_charge_type = "Postpaid"
db_instance_net_type = "Intranet"
master_user_name = "tester"
master_user_password = "Test12345"
allocate_public_connection = true
}
`
const testAccDBInstance_backup = `
resource "alicloud_db_instance" "foo" {
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.t1.small"
db_instance_storage = "10"
instance_charge_type = "Postpaid"
db_instance_net_type = "Intranet"
preferred_backup_period = ["Wednesday","Thursday"]
preferred_backup_time = "00:00Z-01:00Z"
backup_retention_period = 9
}
`
const testAccDBInstance_securityIps = `
resource "alicloud_db_instance" "foo" {
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.t1.small"
db_instance_storage = "10"
instance_charge_type = "Postpaid"
db_instance_net_type = "Intranet"
}
`
const testAccDBInstance_securityIpsConfig = `
resource "alicloud_db_instance" "foo" {
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.t1.small"
db_instance_storage = "10"
instance_charge_type = "Postpaid"
db_instance_net_type = "Intranet"
security_ips = ["10.168.1.12", "100.69.7.112"]
}
`
const testAccDBInstance_class = `
resource "alicloud_db_instance" "foo" {
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.t1.small"
db_instance_storage = "10"
db_instance_net_type = "Intranet"
}
`
const testAccDBInstance_classUpgrade = `
resource "alicloud_db_instance" "foo" {
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.s1.small"
db_instance_storage = "10"
db_instance_net_type = "Intranet"
}
`

View File

@ -151,4 +151,5 @@ resource "alicloud_security_group" "group" {
name = "terraform-test-group" name = "terraform-test-group"
description = "New security group" description = "New security group"
} }
` `

View File

@ -136,9 +136,13 @@ func testAccCheckDiskDestroy(s *terraform.State) error {
} }
const testAccDiskConfig = ` const testAccDiskConfig = `
data "alicloud_zones" "default" {
"available_disk_category"= "cloud_efficiency"
}
resource "alicloud_disk" "foo" { resource "alicloud_disk" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b" availability_zone = "${data.alicloud_zones.default.zones.0.id}"
name = "New-disk" name = "New-disk"
description = "Hello ecs disk." description = "Hello ecs disk."
category = "cloud_efficiency" category = "cloud_efficiency"
@ -146,10 +150,15 @@ resource "alicloud_disk" "foo" {
} }
` `
const testAccDiskConfigWithTags = ` const testAccDiskConfigWithTags = `
data "alicloud_zones" "default" {
"available_disk_category"= "cloud_efficiency"
}
resource "alicloud_disk" "bar" { resource "alicloud_disk" "bar" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b" availability_zone = "${data.alicloud_zones.default.zones.0.id}"
size = "10" category = "cloud_efficiency"
size = "20"
tags { tags {
Name = "TerraformTest" Name = "TerraformTest"
} }

View File

@ -108,6 +108,10 @@ func testAccCheckEIPAssociationDestroy(s *terraform.State) error {
} }
const testAccEIPAssociationConfig = ` const testAccEIPAssociationConfig = `
data "alicloud_zones" "default" {
"available_resource_creation"= "VSwitch"
}
resource "alicloud_vpc" "main" { resource "alicloud_vpc" "main" {
cidr_block = "10.1.0.0/21" cidr_block = "10.1.0.0/21"
} }
@ -115,19 +119,23 @@ resource "alicloud_vpc" "main" {
resource "alicloud_vswitch" "main" { resource "alicloud_vswitch" "main" {
vpc_id = "${alicloud_vpc.main.id}" vpc_id = "${alicloud_vpc.main.id}"
cidr_block = "10.1.1.0/24" cidr_block = "10.1.1.0/24"
availability_zone = "cn-beijing-a" availability_zone = "${data.alicloud_zones.default.zones.0.id}"
depends_on = [ depends_on = [
"alicloud_vpc.main"] "alicloud_vpc.main"]
} }
resource "alicloud_instance" "instance" { resource "alicloud_instance" "instance" {
image_id = "ubuntu_140405_64_40G_cloudinit_20161115.vhd" # cn-beijing
instance_type = "ecs.s1.small"
availability_zone = "cn-beijing-a"
security_groups = ["${alicloud_security_group.group.id}"]
vswitch_id = "${alicloud_vswitch.main.id}" vswitch_id = "${alicloud_vswitch.main.id}"
instance_name = "hello" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
io_optimized = "none"
# series II
instance_type = "ecs.n1.medium"
io_optimized = "optimized"
system_disk_category = "cloud_efficiency"
security_groups = ["${alicloud_security_group.group.id}"]
instance_name = "test_foo"
tags { tags {
Name = "TerraformTest-instance" Name = "TerraformTest-instance"

View File

@ -5,6 +5,7 @@ import (
"log" "log"
"encoding/base64" "encoding/base64"
"encoding/json"
"github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs" "github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
@ -21,8 +22,9 @@ func resourceAliyunInstance() *schema.Resource {
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"availability_zone": &schema.Schema{ "availability_zone": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Optional: true,
ForceNew: true, ForceNew: true,
Computed: true,
}, },
"image_id": &schema.Schema{ "image_id": &schema.Schema{
@ -60,11 +62,6 @@ func resourceAliyunInstance() *schema.Resource {
ValidateFunc: validateInstanceDescription, ValidateFunc: validateInstanceDescription,
}, },
"instance_network_type": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"internet_charge_type": &schema.Schema{ "internet_charge_type": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
@ -104,11 +101,19 @@ func resourceAliyunInstance() *schema.Resource {
Default: "cloud", Default: "cloud",
Optional: true, Optional: true,
ForceNew: true, ForceNew: true,
ValidateFunc: validateAllowedStringValue([]string{
string(ecs.DiskCategoryCloud),
string(ecs.DiskCategoryCloudSSD),
string(ecs.DiskCategoryCloudEfficiency),
string(ecs.DiskCategoryEphemeralSSD),
}),
}, },
"system_disk_size": &schema.Schema{ "system_disk_size": &schema.Schema{
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Computed: true, Computed: true,
ForceNew: true,
ValidateFunc: validateIntegerInRange(40, 500),
}, },
//subnet_id and vswitch_id both exists, cause compatible old version, and aws habit. //subnet_id and vswitch_id both exists, cause compatible old version, and aws habit.
@ -145,7 +150,6 @@ func resourceAliyunInstance() *schema.Resource {
"private_ip": &schema.Schema{ "private_ip": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Optional: true,
Computed: true, Computed: true,
}, },
@ -168,6 +172,11 @@ func resourceAliyunInstance() *schema.Resource {
func resourceAliyunInstanceCreate(d *schema.ResourceData, meta interface{}) error { func resourceAliyunInstanceCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AliyunClient).ecsconn 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) args, err := buildAliyunInstanceArgs(d, meta)
if err != nil { if err != nil {
return err return err
@ -181,7 +190,8 @@ func resourceAliyunInstanceCreate(d *schema.ResourceData, meta interface{}) erro
d.SetId(instanceID) d.SetId(instanceID)
d.Set("password", d.Get("password")) d.Set("password", d.Get("password"))
d.Set("system_disk_category", d.Get("system_disk_category")) //d.Set("system_disk_category", d.Get("system_disk_category"))
//d.Set("system_disk_size", d.Get("system_disk_size"))
if d.Get("allocate_public_ip").(bool) { if d.Get("allocate_public_ip").(bool) {
_, err := conn.AllocatePublicIpAddress(d.Id()) _, err := conn.AllocatePublicIpAddress(d.Id())
@ -207,11 +217,56 @@ func resourceAliyunInstanceCreate(d *schema.ResourceData, meta interface{}) erro
return resourceAliyunInstanceUpdate(d, meta) 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"))
d.Set("system_disk_size", d.Get("system_disk_size"))
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 { func resourceAliyunInstanceRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*AliyunClient) client := meta.(*AliyunClient)
conn := client.ecsconn conn := client.ecsconn
instance, err := client.QueryInstancesById(d.Id()) instance, err := client.QueryInstancesById(d.Id())
if err != nil { if err != nil {
if notFoundError(err) { if notFoundError(err) {
d.SetId("") d.SetId("")
@ -220,7 +275,15 @@ func resourceAliyunInstanceRead(d *schema.ResourceData, meta interface{}) error
return fmt.Errorf("Error DescribeInstanceAttribute: %#v", err) return fmt.Errorf("Error DescribeInstanceAttribute: %#v", err)
} }
log.Printf("[DEBUG] DescribeInstanceAttribute for instance: %#v", instance) disk, diskErr := client.QueryInstanceSystemDisk(d.Id())
if diskErr != nil {
if notFoundError(diskErr) {
d.SetId("")
return nil
}
return fmt.Errorf("Error DescribeSystemDisk: %#v", err)
}
d.Set("instance_name", instance.InstanceName) d.Set("instance_name", instance.InstanceName)
d.Set("description", instance.Description) d.Set("description", instance.Description)
@ -229,6 +292,8 @@ func resourceAliyunInstanceRead(d *schema.ResourceData, meta interface{}) error
d.Set("host_name", instance.HostName) d.Set("host_name", instance.HostName)
d.Set("image_id", instance.ImageId) d.Set("image_id", instance.ImageId)
d.Set("instance_type", instance.InstanceType) d.Set("instance_type", instance.InstanceType)
d.Set("system_disk_category", disk.Category)
d.Set("system_disk_size", disk.Size)
// In Classic network, internet_charge_type is valid in any case, and its default value is 'PayByBanwidth'. // In Classic network, internet_charge_type is valid in any case, and its default value is 'PayByBanwidth'.
// In VPC network, internet_charge_type is valid when instance has public ip, and its default value is 'PayByBanwidth'. // In VPC network, internet_charge_type is valid when instance has public ip, and its default value is 'PayByBanwidth'.
@ -244,10 +309,6 @@ func resourceAliyunInstanceRead(d *schema.ResourceData, meta interface{}) error
d.Set("io_optimized", "none") d.Set("io_optimized", "none")
} }
log.Printf("instance.InternetChargeType: %#v", instance.InternetChargeType)
d.Set("instance_network_type", instance.InstanceNetworkType)
if d.Get("subnet_id").(string) != "" || d.Get("vswitch_id").(string) != "" { if d.Get("subnet_id").(string) != "" || d.Get("vswitch_id").(string) != "" {
ipAddress := instance.VpcAttributes.PrivateIpAddress.IpAddress[0] ipAddress := instance.VpcAttributes.PrivateIpAddress.IpAddress[0]
d.Set("private_ip", ipAddress) d.Set("private_ip", ipAddress)
@ -414,33 +475,71 @@ func resourceAliyunInstanceDelete(d *schema.ResourceData, meta interface{}) erro
return nil return nil
} }
func buildAliyunRunInstancesArgs(d *schema.ResourceData, meta interface{}) (*ecs.RunInstanceArgs, error) {
args := &ecs.RunInstanceArgs{
MaxAmount: DEFAULT_INSTANCE_COUNT,
MinAmount: DEFAULT_INSTANCE_COUNT,
}
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 == "" {
args.NetworkType = string(ClassicNet)
}
return args, nil
}
func buildAliyunInstanceArgs(d *schema.ResourceData, meta interface{}) (*ecs.CreateInstanceArgs, error) { func buildAliyunInstanceArgs(d *schema.ResourceData, meta interface{}) (*ecs.CreateInstanceArgs, error) {
client := meta.(*AliyunClient) client := meta.(*AliyunClient)
args := &ecs.CreateInstanceArgs{ args := &ecs.CreateInstanceArgs{
RegionId: getRegion(d, meta), RegionId: getRegion(d, meta),
InstanceType: d.Get("instance_type").(string), InstanceType: d.Get("instance_type").(string),
PrivateIpAddress: d.Get("private_ip").(string),
} }
imageID := d.Get("image_id").(string) imageID := d.Get("image_id").(string)
args.ImageId = imageID args.ImageId = imageID
systemDiskCategory := ecs.DiskCategory(d.Get("system_disk_category").(string))
systemDiskSize := d.Get("system_disk_size").(int)
zoneID := d.Get("availability_zone").(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 { args.SystemDisk = ecs.SystemDiskType{
return nil, err Category: systemDiskCategory,
Size: systemDiskSize,
} }
args.ZoneId = zoneID
sgs, ok := d.GetOk("security_groups") sgs, ok := d.GetOk("security_groups")
if ok { if ok {
@ -451,17 +550,6 @@ func buildAliyunInstanceArgs(d *schema.ResourceData, meta interface{}) (*ecs.Cre
if err == nil { if err == nil {
args.SecurityGroupId = sg0 args.SecurityGroupId = sg0
} }
}
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 != "" { if v := d.Get("instance_name").(string); v != "" {
@ -472,7 +560,7 @@ func buildAliyunInstanceArgs(d *schema.ResourceData, meta interface{}) (*ecs.Cre
args.Description = v args.Description = v
} }
log.Printf("[DEBUG] internet_charge_type is %s", d.Get("internet_charge_type").(string)) log.Printf("[DEBUG] SystemDisk is %d", systemDiskSize)
if v := d.Get("internet_charge_type").(string); v != "" { if v := d.Get("internet_charge_type").(string); v != "" {
args.InternetChargeType = common.InternetChargeType(v) args.InternetChargeType = common.InternetChargeType(v)
} }
@ -490,7 +578,11 @@ func buildAliyunInstanceArgs(d *schema.ResourceData, meta interface{}) (*ecs.Cre
} }
if v := d.Get("io_optimized").(string); v != "" { 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) vswitchValue := d.Get("subnet_id").(string)

View File

@ -56,6 +56,7 @@ func TestAccAlicloudInstance_basic(t *testing.T) {
"alicloud_instance.foo", "alicloud_instance.foo",
"internet_charge_type", "internet_charge_type",
"PayByBandwidth"), "PayByBandwidth"),
testAccCheckSystemDiskSize("alicloud_instance.foo", 80),
), ),
}, },
@ -355,10 +356,6 @@ func TestAccAlicloudInstance_tags(t *testing.T) {
Config: testAccCheckInstanceConfigTagsUpdate, Config: testAccCheckInstanceConfigTagsUpdate,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckInstanceExists("alicloud_instance.foo", &instance), testAccCheckInstanceExists("alicloud_instance.foo", &instance),
resource.TestCheckResourceAttr(
"alicloud_instance.foo",
"tags.foo",
""),
resource.TestCheckResourceAttr( resource.TestCheckResourceAttr(
"alicloud_instance.foo", "alicloud_instance.foo",
"tags.bar", "tags.bar",
@ -418,8 +415,8 @@ func TestAccAlicloudInstance_privateIP(t *testing.T) {
testCheckPrivateIP := func() resource.TestCheckFunc { testCheckPrivateIP := func() resource.TestCheckFunc {
return func(*terraform.State) error { return func(*terraform.State) error {
privateIP := instance.VpcAttributes.PrivateIpAddress.IpAddress[0] privateIP := instance.VpcAttributes.PrivateIpAddress.IpAddress[0]
if privateIP != "172.16.0.229" { if privateIP == "" {
return fmt.Errorf("bad private IP: %s", privateIP) return fmt.Errorf("can't get private IP")
} }
return nil return nil
@ -445,14 +442,14 @@ func TestAccAlicloudInstance_privateIP(t *testing.T) {
}) })
} }
func TestAccAlicloudInstance_associatePublicIPAndPrivateIP(t *testing.T) { func TestAccAlicloudInstance_associatePublicIP(t *testing.T) {
var instance ecs.InstanceAttributesType var instance ecs.InstanceAttributesType
testCheckPrivateIP := func() resource.TestCheckFunc { testCheckPrivateIP := func() resource.TestCheckFunc {
return func(*terraform.State) error { return func(*terraform.State) error {
privateIP := instance.VpcAttributes.PrivateIpAddress.IpAddress[0] privateIP := instance.VpcAttributes.PrivateIpAddress.IpAddress[0]
if privateIP != "172.16.0.229" { if privateIP == "" {
return fmt.Errorf("bad private IP: %s", privateIP) return fmt.Errorf("can't get private IP")
} }
return nil return nil
@ -468,7 +465,7 @@ func TestAccAlicloudInstance_associatePublicIPAndPrivateIP(t *testing.T) {
CheckDestroy: testAccCheckInstanceDestroy, CheckDestroy: testAccCheckInstanceDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ resource.TestStep{
Config: testAccInstanceConfigAssociatePublicIPAndPrivateIP, Config: testAccInstanceConfigAssociatePublicIP,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckInstanceExists("alicloud_instance.foo", &instance), testAccCheckInstanceExists("alicloud_instance.foo", &instance),
testCheckPrivateIP(), testCheckPrivateIP(),
@ -597,6 +594,36 @@ func testAccCheckInstanceDestroyWithProvider(s *terraform.State, provider *schem
return nil return nil
} }
func testAccCheckSystemDiskSize(n string, size int) resource.TestCheckFunc {
return func(s *terraform.State) error {
providers := []*schema.Provider{testAccProvider}
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
for _, provider := range providers {
if provider.Meta() == nil {
continue
}
client := provider.Meta().(*AliyunClient)
systemDisk, err := client.QueryInstanceSystemDisk(rs.Primary.ID)
if err != nil {
log.Printf("[ERROR]get system disk size error: %#v", err)
return err
}
if systemDisk.Size != size {
return fmt.Errorf("system disk size not equal %d, the instance system size is %d",
size, systemDisk.Size)
}
}
return nil
}
}
const testAccInstanceConfig = ` const testAccInstanceConfig = `
resource "alicloud_security_group" "tf_test_foo" { resource "alicloud_security_group" "tf_test_foo" {
name = "tf_test_foo" name = "tf_test_foo"
@ -609,11 +636,10 @@ resource "alicloud_security_group" "tf_test_bar" {
} }
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing
availability_zone = "cn-beijing-b"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
system_disk_category = "cloud_ssd" system_disk_category = "cloud_ssd"
system_disk_size = 80
instance_type = "ecs.n1.small" instance_type = "ecs.n1.small"
internet_charge_type = "PayByBandwidth" internet_charge_type = "PayByBandwidth"
@ -628,15 +654,20 @@ resource "alicloud_instance" "foo" {
} }
` `
const testAccInstanceConfigVPC = ` const testAccInstanceConfigVPC = `
data "alicloud_zones" "default" {
"available_disk_category"= "cloud_efficiency"
"available_resource_creation"= "VSwitch"
}
resource "alicloud_vpc" "foo" { resource "alicloud_vpc" "foo" {
name = "tf_test_foo" name = "tf_test_foo"
cidr_block = "172.16.0.0/12" cidr_block = "172.16.0.0/12"
} }
resource "alicloud_vswitch" "foo" { resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}" vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "172.16.0.0/21" 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" { resource "alicloud_security_group" "tf_test_foo" {
@ -647,7 +678,6 @@ resource "alicloud_security_group" "tf_test_foo" {
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
vswitch_id = "${alicloud_vswitch.foo.id}" vswitch_id = "${alicloud_vswitch.foo.id}"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
@ -666,15 +696,20 @@ resource "alicloud_instance" "foo" {
` `
const testAccInstanceConfigUserData = ` const testAccInstanceConfigUserData = `
data "alicloud_zones" "default" {
"available_disk_category"= "cloud_efficiency"
"available_resource_creation"= "VSwitch"
}
resource "alicloud_vpc" "foo" { resource "alicloud_vpc" "foo" {
name = "tf_test_foo" name = "tf_test_foo"
cidr_block = "172.16.0.0/12" cidr_block = "172.16.0.0/12"
} }
resource "alicloud_vswitch" "foo" { resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}" vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "172.16.0.0/21" 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" { resource "alicloud_security_group" "tf_test_foo" {
@ -685,7 +720,6 @@ resource "alicloud_security_group" "tf_test_foo" {
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
vswitch_id = "${alicloud_vswitch.foo.id}" vswitch_id = "${alicloud_vswitch.foo.id}"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
# series II # series II
@ -725,24 +759,22 @@ resource "alicloud_security_group" "tf_test_bar" {
} }
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
provider = "alicloud.beijing" provider = "alicloud.beijing"
availability_zone = "cn-beijing-b" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
internet_charge_type = "PayByBandwidth" internet_charge_type = "PayByBandwidth"
instance_type = "ecs.n1.medium" instance_type = "ecs.n1.medium"
io_optimized = "optimized" io_optimized = "optimized"
system_disk_category = "cloud_efficiency" system_disk_category = "cloud_efficiency"
security_groups = ["${alicloud_security_group.tf_test_foo.id}"] security_groups = ["${alicloud_security_group.tf_test_foo.id}"]
instance_name = "test_foo" instance_name = "test_foo"
} }
resource "alicloud_instance" "bar" { resource "alicloud_instance" "bar" {
# cn-shanghai # cn-shanghai
provider = "alicloud.shanghai" provider = "alicloud.shanghai"
availability_zone = "cn-shanghai-b"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
internet_charge_type = "PayByBandwidth" internet_charge_type = "PayByBandwidth"
@ -768,7 +800,6 @@ resource "alicloud_security_group" "tf_test_bar" {
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
instance_type = "ecs.s2.large" instance_type = "ecs.s2.large"
@ -776,6 +807,7 @@ resource "alicloud_instance" "foo" {
security_groups = ["${alicloud_security_group.tf_test_foo.id}", "${alicloud_security_group.tf_test_bar.id}"] security_groups = ["${alicloud_security_group.tf_test_foo.id}", "${alicloud_security_group.tf_test_bar.id}"]
instance_name = "test_foo" instance_name = "test_foo"
io_optimized = "optimized" io_optimized = "optimized"
system_disk_category = "cloud_efficiency"
}` }`
const testAccInstanceConfig_multiSecurityGroup_add = ` const testAccInstanceConfig_multiSecurityGroup_add = `
@ -796,7 +828,6 @@ resource "alicloud_security_group" "tf_test_add_sg" {
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
instance_type = "ecs.s2.large" instance_type = "ecs.s2.large"
@ -805,6 +836,7 @@ resource "alicloud_instance" "foo" {
"${alicloud_security_group.tf_test_add_sg.id}"] "${alicloud_security_group.tf_test_add_sg.id}"]
instance_name = "test_foo" instance_name = "test_foo"
io_optimized = "optimized" io_optimized = "optimized"
system_disk_category = "cloud_efficiency"
} }
` `
@ -814,9 +846,30 @@ resource "alicloud_security_group" "tf_test_foo" {
description = "foo" description = "foo"
} }
resource "alicloud_security_group_rule" "http-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "internet"
policy = "accept"
port_range = "80/80"
priority = 1
security_group_id = "${alicloud_security_group.tf_test_foo.id}"
cidr_ip = "0.0.0.0/0"
}
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_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
instance_type = "ecs.s2.large" instance_type = "ecs.s2.large"
@ -824,6 +877,7 @@ resource "alicloud_instance" "foo" {
security_groups = ["${alicloud_security_group.tf_test_foo.id}"] security_groups = ["${alicloud_security_group.tf_test_foo.id}"]
instance_name = "test_foo" instance_name = "test_foo"
io_optimized = "optimized" io_optimized = "optimized"
system_disk_category = "cloud_efficiency"
} }
` `
@ -836,27 +890,32 @@ resource "alicloud_security_group" "tf_test_foo" {
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
instance_type = "ecs.s2.large" instance_type = "ecs.s2.large"
internet_charge_type = "PayByBandwidth" internet_charge_type = "PayByBandwidth"
security_groups = ["${alicloud_security_group.tf_test_foo.*.id}"] security_groups = ["${alicloud_security_group.tf_test_foo.*.id}"]
instance_name = "test_foo" instance_name = "test_foo"
io_optimized = "none" io_optimized = "optimized"
system_disk_category = "cloud_efficiency"
} }
` `
const testAccInstanceNetworkInstanceSecurityGroups = ` const testAccInstanceNetworkInstanceSecurityGroups = `
data "alicloud_zones" "default" {
"available_disk_category"= "cloud_efficiency"
"available_resource_creation"= "VSwitch"
}
resource "alicloud_vpc" "foo" { resource "alicloud_vpc" "foo" {
name = "tf_test_foo" name = "tf_test_foo"
cidr_block = "172.16.0.0/12" cidr_block = "172.16.0.0/12"
} }
resource "alicloud_vswitch" "foo" { resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}" vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "172.16.0.0/21" 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" { resource "alicloud_security_group" "tf_test_foo" {
@ -867,7 +926,6 @@ resource "alicloud_security_group" "tf_test_foo" {
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
vswitch_id = "${alicloud_vswitch.foo.id}" vswitch_id = "${alicloud_vswitch.foo.id}"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
@ -892,7 +950,6 @@ resource "alicloud_security_group" "tf_test_foo" {
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
# series II # series II
@ -918,7 +975,6 @@ resource "alicloud_security_group" "tf_test_foo" {
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
# series II # series II
@ -941,9 +997,30 @@ resource "alicloud_security_group" "tf_test_foo" {
description = "foo" description = "foo"
} }
resource "alicloud_security_group_rule" "http-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "internet"
policy = "accept"
port_range = "80/80"
priority = 1
security_group_id = "${alicloud_security_group.tf_test_foo.id}"
cidr_ip = "0.0.0.0/0"
}
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_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
# series II # series II
@ -965,9 +1042,30 @@ resource "alicloud_security_group" "tf_test_foo" {
description = "foo" description = "foo"
} }
resource "alicloud_security_group_rule" "http-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "internet"
policy = "accept"
port_range = "80/80"
priority = 1
security_group_id = "${alicloud_security_group.tf_test_foo.id}"
cidr_ip = "0.0.0.0/0"
}
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_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
# series II # series II
@ -984,15 +1082,20 @@ resource "alicloud_instance" "foo" {
` `
const testAccInstanceConfigPrivateIP = ` const testAccInstanceConfigPrivateIP = `
data "alicloud_zones" "default" {
"available_disk_category"= "cloud_efficiency"
"available_resource_creation"= "VSwitch"
}
resource "alicloud_vpc" "foo" { resource "alicloud_vpc" "foo" {
name = "tf_test_foo" name = "tf_test_foo"
cidr_block = "172.16.0.0/12" cidr_block = "172.16.0.0/12"
} }
resource "alicloud_vswitch" "foo" { resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}" vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "172.16.0.0/24" 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" { resource "alicloud_security_group" "tf_test_foo" {
@ -1003,11 +1106,9 @@ resource "alicloud_security_group" "tf_test_foo" {
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
security_groups = ["${alicloud_security_group.tf_test_foo.id}"] security_groups = ["${alicloud_security_group.tf_test_foo.id}"]
vswitch_id = "${alicloud_vswitch.foo.id}" vswitch_id = "${alicloud_vswitch.foo.id}"
private_ip = "172.16.0.229"
# series II # series II
instance_type = "ecs.n1.medium" instance_type = "ecs.n1.medium"
@ -1017,16 +1118,21 @@ resource "alicloud_instance" "foo" {
instance_name = "test_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" { resource "alicloud_vpc" "foo" {
name = "tf_test_foo" name = "tf_test_foo"
cidr_block = "172.16.0.0/12" cidr_block = "172.16.0.0/12"
} }
resource "alicloud_vswitch" "foo" { resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}" vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "172.16.0.0/24" 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" { resource "alicloud_security_group" "tf_test_foo" {
@ -1037,11 +1143,9 @@ resource "alicloud_security_group" "tf_test_foo" {
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
security_groups = ["${alicloud_security_group.tf_test_foo.id}"] security_groups = ["${alicloud_security_group.tf_test_foo.id}"]
vswitch_id = "${alicloud_vswitch.foo.id}" vswitch_id = "${alicloud_vswitch.foo.id}"
private_ip = "172.16.0.229"
allocate_public_ip = "true" allocate_public_ip = "true"
internet_max_bandwidth_out = 5 internet_max_bandwidth_out = 5
internet_charge_type = "PayByBandwidth" internet_charge_type = "PayByBandwidth"
@ -1055,52 +1159,56 @@ resource "alicloud_instance" "foo" {
} }
` `
const testAccVpcInstanceWithSecurityRule = ` const testAccVpcInstanceWithSecurityRule = `
data "alicloud_zones" "default" {
"available_disk_category"= "cloud_efficiency"
"available_resource_creation"= "VSwitch"
}
resource "alicloud_vpc" "foo" { resource "alicloud_vpc" "foo" {
name = "tf_test_foo" name = "tf_test_foo"
cidr_block = "10.1.0.0/21" cidr_block = "10.1.0.0/21"
} }
resource "alicloud_vswitch" "foo" { resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}" vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "10.1.1.0/24" 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" { resource "alicloud_security_group" "tf_test_foo" {
name = "tf_test_foo" name = "tf_test_foo"
description = "foo" description = "foo"
vpc_id = "${alicloud_vpc.foo.id}" vpc_id = "${alicloud_vpc.foo.id}"
} }
resource "alicloud_security_group_rule" "ingress" { resource "alicloud_security_group_rule" "ingress" {
type = "ingress" type = "ingress"
ip_protocol = "tcp" ip_protocol = "tcp"
nic_type = "intranet" nic_type = "intranet"
policy = "accept" policy = "accept"
port_range = "22/22" port_range = "22/22"
priority = 1 priority = 1
security_group_id = "${alicloud_security_group.tf_test_foo.id}" security_group_id = "${alicloud_security_group.tf_test_foo.id}"
cidr_ip = "0.0.0.0/0" cidr_ip = "0.0.0.0/0"
} }
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-c" security_groups = ["${alicloud_security_group.tf_test_foo.id}"]
security_groups = ["${alicloud_security_group.tf_test_foo.id}"]
vswitch_id = "${alicloud_vswitch.foo.id}" vswitch_id = "${alicloud_vswitch.foo.id}"
allocate_public_ip = true allocate_public_ip = true
# series II # series II
instance_charge_type = "PostPaid" instance_charge_type = "PostPaid"
instance_type = "ecs.n1.small" instance_type = "ecs.n1.small"
internet_charge_type = "PayByBandwidth" internet_charge_type = "PayByBandwidth"
internet_max_bandwidth_out = 5 internet_max_bandwidth_out = 5
system_disk_category = "cloud_efficiency" system_disk_category = "cloud_efficiency"
image_id = "ubuntu_140405_64_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_64_40G_cloudinit_20161115.vhd"
instance_name = "test_foo" instance_name = "test_foo"
io_optimized = "optimized" io_optimized = "optimized"
} }
` `

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"log" "log"
@ -71,7 +72,7 @@ func resourceAliyunNatGateway() *schema.Resource {
func resourceAliyunNatGatewayCreate(d *schema.ResourceData, meta interface{}) error { func resourceAliyunNatGatewayCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AliyunClient).vpcconn conn := meta.(*AliyunClient).vpcconn
args := &CreateNatGatewayArgs{ args := &ecs.CreateNatGatewayArgs{
RegionId: getRegion(d, meta), RegionId: getRegion(d, meta),
VpcId: d.Get("vpc_id").(string), VpcId: d.Get("vpc_id").(string),
Spec: d.Get("spec").(string), Spec: d.Get("spec").(string),
@ -79,11 +80,11 @@ func resourceAliyunNatGatewayCreate(d *schema.ResourceData, meta interface{}) er
bandwidthPackages := d.Get("bandwidth_packages").([]interface{}) bandwidthPackages := d.Get("bandwidth_packages").([]interface{})
bandwidthPackageTypes := []BandwidthPackageType{} bandwidthPackageTypes := []ecs.BandwidthPackageType{}
for _, e := range bandwidthPackages { for _, e := range bandwidthPackages {
pack := e.(map[string]interface{}) pack := e.(map[string]interface{})
bandwidthPackage := BandwidthPackageType{ bandwidthPackage := ecs.BandwidthPackageType{
IpCount: pack["ip_count"].(int), IpCount: pack["ip_count"].(int),
Bandwidth: pack["bandwidth"].(int), Bandwidth: pack["bandwidth"].(int),
} }
@ -106,8 +107,7 @@ func resourceAliyunNatGatewayCreate(d *schema.ResourceData, meta interface{}) er
if v, ok := d.GetOk("description"); ok { if v, ok := d.GetOk("description"); ok {
args.Description = v.(string) args.Description = v.(string)
} }
resp, err := conn.CreateNatGateway(args)
resp, err := CreateNatGateway(conn, args)
if err != nil { if err != nil {
return fmt.Errorf("CreateNatGateway got error: %#v", err) return fmt.Errorf("CreateNatGateway got error: %#v", err)
} }
@ -142,6 +142,7 @@ func resourceAliyunNatGatewayRead(d *schema.ResourceData, meta interface{}) erro
func resourceAliyunNatGatewayUpdate(d *schema.ResourceData, meta interface{}) error { func resourceAliyunNatGatewayUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*AliyunClient) client := meta.(*AliyunClient)
conn := client.vpcconn
natGateway, err := client.DescribeNatGateway(d.Id()) natGateway, err := client.DescribeNatGateway(d.Id())
if err != nil { if err != nil {
@ -150,7 +151,7 @@ func resourceAliyunNatGatewayUpdate(d *schema.ResourceData, meta interface{}) er
d.Partial(true) d.Partial(true)
attributeUpdate := false attributeUpdate := false
args := &ModifyNatGatewayAttributeArgs{ args := &ecs.ModifyNatGatewayAttributeArgs{
RegionId: natGateway.RegionId, RegionId: natGateway.RegionId,
NatGatewayId: natGateway.NatGatewayId, NatGatewayId: natGateway.NatGatewayId,
} }
@ -183,28 +184,28 @@ func resourceAliyunNatGatewayUpdate(d *schema.ResourceData, meta interface{}) er
} }
if attributeUpdate { if attributeUpdate {
if err := ModifyNatGatewayAttribute(client.vpcconn, args); err != nil { if err := conn.ModifyNatGatewayAttribute(args); err != nil {
return err return err
} }
} }
if d.HasChange("spec") { if d.HasChange("spec") {
d.SetPartial("spec") d.SetPartial("spec")
var spec NatGatewaySpec var spec ecs.NatGatewaySpec
if v, ok := d.GetOk("spec"); ok { if v, ok := d.GetOk("spec"); ok {
spec = NatGatewaySpec(v.(string)) spec = ecs.NatGatewaySpec(v.(string))
} else { } else {
// set default to small spec // set default to small spec
spec = NatGatewaySmallSpec spec = ecs.NatGatewaySmallSpec
} }
args := &ModifyNatGatewaySpecArgs{ args := &ecs.ModifyNatGatewaySpecArgs{
RegionId: natGateway.RegionId, RegionId: natGateway.RegionId,
NatGatewayId: natGateway.NatGatewayId, NatGatewayId: natGateway.NatGatewayId,
Spec: spec, Spec: spec,
} }
err := ModifyNatGatewaySpec(client.vpcconn, args) err := conn.ModifyNatGatewaySpec(args)
if err != nil { if err != nil {
return fmt.Errorf("%#v %#v", err, *args) return fmt.Errorf("%#v %#v", err, *args)
} }
@ -218,10 +219,11 @@ func resourceAliyunNatGatewayUpdate(d *schema.ResourceData, meta interface{}) er
func resourceAliyunNatGatewayDelete(d *schema.ResourceData, meta interface{}) error { func resourceAliyunNatGatewayDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*AliyunClient) client := meta.(*AliyunClient)
conn := client.vpcconn
return resource.Retry(5*time.Minute, func() *resource.RetryError { return resource.Retry(5*time.Minute, func() *resource.RetryError {
packages, err := DescribeBandwidthPackages(client.vpcconn, &DescribeBandwidthPackagesArgs{ packages, err := conn.DescribeBandwidthPackages(&ecs.DescribeBandwidthPackagesArgs{
RegionId: getRegion(d, meta), RegionId: getRegion(d, meta),
NatGatewayId: d.Id(), NatGatewayId: d.Id(),
}) })
@ -232,7 +234,7 @@ func resourceAliyunNatGatewayDelete(d *schema.ResourceData, meta interface{}) er
retry := false retry := false
for _, pack := range packages { for _, pack := range packages {
err = DeleteBandwidthPackage(client.vpcconn, &DeleteBandwidthPackageArgs{ err = conn.DeleteBandwidthPackage(&ecs.DeleteBandwidthPackageArgs{
RegionId: getRegion(d, meta), RegionId: getRegion(d, meta),
BandwidthPackageId: pack.BandwidthPackageId, BandwidthPackageId: pack.BandwidthPackageId,
}) })
@ -251,12 +253,12 @@ func resourceAliyunNatGatewayDelete(d *schema.ResourceData, meta interface{}) er
return resource.RetryableError(fmt.Errorf("Bandwidth package in use - trying again while it is deleted.")) return resource.RetryableError(fmt.Errorf("Bandwidth package in use - trying again while it is deleted."))
} }
args := &DeleteNatGatewayArgs{ args := &ecs.DeleteNatGatewayArgs{
RegionId: client.Region, RegionId: client.Region,
NatGatewayId: d.Id(), NatGatewayId: d.Id(),
} }
err = DeleteNatGateway(client.vpcconn, args) err = conn.DeleteNatGateway(args)
if err != nil { if err != nil {
er, _ := err.(*common.Error) er, _ := err.(*common.Error)
if er.ErrorResponse.Code == DependencyViolationBandwidthPackages { if er.ErrorResponse.Code == DependencyViolationBandwidthPackages {
@ -264,11 +266,11 @@ func resourceAliyunNatGatewayDelete(d *schema.ResourceData, meta interface{}) er
} }
} }
describeArgs := &DescribeNatGatewaysArgs{ describeArgs := &ecs.DescribeNatGatewaysArgs{
RegionId: client.Region, RegionId: client.Region,
NatGatewayId: d.Id(), NatGatewayId: d.Id(),
} }
gw, _, gwErr := DescribeNatGateways(client.vpcconn, describeArgs) gw, _, gwErr := conn.DescribeNatGateways(describeArgs)
if gwErr != nil { if gwErr != nil {
log.Printf("[ERROR] Describe NatGateways failed.") log.Printf("[ERROR] Describe NatGateways failed.")

View File

@ -3,13 +3,14 @@ package alicloud
import ( import (
"fmt" "fmt"
"github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"testing" "testing"
) )
func TestAccAlicloudNatGateway_basic(t *testing.T) { func TestAccAlicloudNatGateway_basic(t *testing.T) {
var nat NatGatewaySetType var nat ecs.NatGatewaySetType
testCheck := func(*terraform.State) error { testCheck := func(*terraform.State) error {
if nat.BusinessStatus != "Normal" { if nat.BusinessStatus != "Normal" {
@ -55,7 +56,7 @@ func TestAccAlicloudNatGateway_basic(t *testing.T) {
} }
func TestAccAlicloudNatGateway_spec(t *testing.T) { func TestAccAlicloudNatGateway_spec(t *testing.T) {
var nat NatGatewaySetType var nat ecs.NatGatewaySetType
resource.Test(t, resource.TestCase{ resource.Test(t, resource.TestCase{
PreCheck: func() { PreCheck: func() {
@ -95,7 +96,7 @@ func TestAccAlicloudNatGateway_spec(t *testing.T) {
} }
func testAccCheckNatGatewayExists(n string, nat *NatGatewaySetType) resource.TestCheckFunc { func testAccCheckNatGatewayExists(n string, nat *ecs.NatGatewaySetType) resource.TestCheckFunc {
return func(s *terraform.State) error { return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n] rs, ok := s.RootModule().Resources[n]
if !ok { if !ok {
@ -151,6 +152,10 @@ func testAccCheckNatGatewayDestroy(s *terraform.State) error {
} }
const testAccNatGatewayConfig = ` const testAccNatGatewayConfig = `
data "alicloud_zones" "default" {
"available_resource_creation"= "VSwitch"
}
resource "alicloud_vpc" "foo" { resource "alicloud_vpc" "foo" {
name = "tf_test_foo" name = "tf_test_foo"
cidr_block = "172.16.0.0/12" cidr_block = "172.16.0.0/12"
@ -159,7 +164,7 @@ resource "alicloud_vpc" "foo" {
resource "alicloud_vswitch" "foo" { resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}" vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "172.16.0.0/21" 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" { resource "alicloud_nat_gateway" "foo" {
@ -169,11 +174,11 @@ resource "alicloud_nat_gateway" "foo" {
bandwidth_packages = [{ bandwidth_packages = [{
ip_count = 1 ip_count = 1
bandwidth = 5 bandwidth = 5
zone = "cn-beijing-b" zone = "${data.alicloud_zones.default.zones.0.id}"
}, { }, {
ip_count = 2 ip_count = 2
bandwidth = 10 bandwidth = 10
zone = "cn-beijing-b" zone = "${data.alicloud_zones.default.zones.0.id}"
}] }]
depends_on = [ depends_on = [
"alicloud_vswitch.foo"] "alicloud_vswitch.foo"]
@ -181,6 +186,10 @@ resource "alicloud_nat_gateway" "foo" {
` `
const testAccNatGatewayConfigSpec = ` const testAccNatGatewayConfigSpec = `
data "alicloud_zones" "default" {
"available_resource_creation"= "VSwitch"
}
resource "alicloud_vpc" "foo" { resource "alicloud_vpc" "foo" {
name = "tf_test_foo" name = "tf_test_foo"
cidr_block = "172.16.0.0/12" cidr_block = "172.16.0.0/12"
@ -189,7 +198,7 @@ resource "alicloud_vpc" "foo" {
resource "alicloud_vswitch" "foo" { resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}" vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "172.16.0.0/21" 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" { resource "alicloud_nat_gateway" "foo" {
@ -199,11 +208,11 @@ resource "alicloud_nat_gateway" "foo" {
bandwidth_packages = [{ bandwidth_packages = [{
ip_count = 1 ip_count = 1
bandwidth = 5 bandwidth = 5
zone = "cn-beijing-b" zone = "${data.alicloud_zones.default.zones.0.id}"
}, { }, {
ip_count = 2 ip_count = 2
bandwidth = 10 bandwidth = 10
zone = "cn-beijing-b" zone = "${data.alicloud_zones.default.zones.0.id}"
}] }]
depends_on = [ depends_on = [
"alicloud_vswitch.foo"] "alicloud_vswitch.foo"]
@ -211,6 +220,10 @@ resource "alicloud_nat_gateway" "foo" {
` `
const testAccNatGatewayConfigSpecUpgrade = ` const testAccNatGatewayConfigSpecUpgrade = `
data "alicloud_zones" "default" {
"available_resource_creation"= "VSwitch"
}
resource "alicloud_vpc" "foo" { resource "alicloud_vpc" "foo" {
name = "tf_test_foo" name = "tf_test_foo"
cidr_block = "172.16.0.0/12" cidr_block = "172.16.0.0/12"
@ -219,7 +232,7 @@ resource "alicloud_vpc" "foo" {
resource "alicloud_vswitch" "foo" { resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}" vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "172.16.0.0/21" 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" { resource "alicloud_nat_gateway" "foo" {
@ -229,11 +242,11 @@ resource "alicloud_nat_gateway" "foo" {
bandwidth_packages = [{ bandwidth_packages = [{
ip_count = 1 ip_count = 1
bandwidth = 5 bandwidth = 5
zone = "cn-beijing-b" zone = "${data.alicloud_zones.default.zones.0.id}"
}, { }, {
ip_count = 2 ip_count = 2
bandwidth = 10 bandwidth = 10
zone = "cn-beijing-b" zone = "${data.alicloud_zones.default.zones.0.id}"
}] }]
depends_on = [ depends_on = [
"alicloud_vswitch.foo"] "alicloud_vswitch.foo"]

View File

@ -6,7 +6,6 @@ import (
"github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs" "github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"time" "time"
) )
@ -145,6 +144,7 @@ func resourceAliyunSecurityGroupDelete(d *schema.ResourceData, meta interface{})
return resource.RetryableError(fmt.Errorf("Security group in use - trying again while it is deleted.")) return resource.RetryableError(fmt.Errorf("Security group in use - trying again while it is deleted."))
}) })
} }
func buildAliyunSecurityGroupArgs(d *schema.ResourceData, meta interface{}) (*ecs.CreateSecurityGroupArgs, error) { func buildAliyunSecurityGroupArgs(d *schema.ResourceData, meta interface{}) (*ecs.CreateSecurityGroupArgs, error) {

View File

@ -34,6 +34,7 @@ func resourceAliyunSecurityGroupRule() *schema.Resource {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
ForceNew: true, ForceNew: true,
Computed: true,
ValidateFunc: validateSecurityRuleNicType, ValidateFunc: validateSecurityRuleNicType,
}, },
@ -67,7 +68,6 @@ func resourceAliyunSecurityGroupRule() *schema.Resource {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
ForceNew: true, ForceNew: true,
Default: "0.0.0.0/0",
}, },
"source_security_group_id": &schema.Schema{ "source_security_group_id": &schema.Schema{
@ -86,15 +86,17 @@ func resourceAliyunSecurityGroupRule() *schema.Resource {
} }
func resourceAliyunSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{}) error { func resourceAliyunSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AliyunClient).ecsconn client := meta.(*AliyunClient)
conn := client.ecsconn
ruleType := d.Get("type").(string) direction := d.Get("type").(string)
sgId := d.Get("security_group_id").(string) sgId := d.Get("security_group_id").(string)
ptl := d.Get("ip_protocol").(string) ptl := d.Get("ip_protocol").(string)
port := d.Get("port_range").(string) port := d.Get("port_range").(string)
nicType := d.Get("nic_type").(string)
var autherr error var autherr error
switch GroupRuleDirection(ruleType) { switch GroupRuleDirection(direction) {
case GroupRuleIngress: case GroupRuleIngress:
args, err := buildAliyunSecurityIngressArgs(d, meta) args, err := buildAliyunSecurityIngressArgs(d, meta)
if err != nil { if err != nil {
@ -114,10 +116,11 @@ func resourceAliyunSecurityGroupRuleCreate(d *schema.ResourceData, meta interfac
if autherr != nil { if autherr != nil {
return fmt.Errorf( return fmt.Errorf(
"Error authorizing security group rule type %s: %s", "Error authorizing security group rule type %s: %s",
ruleType, autherr) direction, autherr)
} }
d.SetId(sgId + ":" + ruleType + ":" + ptl + ":" + port) d.SetId(sgId + ":" + direction + ":" + ptl + ":" + port + ":" + nicType)
return resourceAliyunSecurityGroupRuleRead(d, meta) return resourceAliyunSecurityGroupRuleRead(d, meta)
} }
@ -125,10 +128,11 @@ func resourceAliyunSecurityGroupRuleRead(d *schema.ResourceData, meta interface{
client := meta.(*AliyunClient) client := meta.(*AliyunClient)
parts := strings.Split(d.Id(), ":") parts := strings.Split(d.Id(), ":")
sgId := parts[0] sgId := parts[0]
types := parts[1] direction := parts[1]
ip_protocol := parts[2] ip_protocol := parts[2]
port_range := parts[3] port_range := parts[3]
rule, err := client.DescribeSecurityGroupRule(sgId, types, ip_protocol, port_range) nic_type := parts[4]
rule, err := client.DescribeSecurityGroupRule(sgId, direction, nic_type, ip_protocol, port_range)
if err != nil { if err != nil {
if notFoundError(err) { if notFoundError(err) {
@ -137,7 +141,7 @@ func resourceAliyunSecurityGroupRuleRead(d *schema.ResourceData, meta interface{
} }
return fmt.Errorf("Error SecurityGroup rule: %#v", err) return fmt.Errorf("Error SecurityGroup rule: %#v", err)
} }
log.Printf("[WARN]sg %s, type %s, protocol %s, port %s, rule %#v", sgId, types, ip_protocol, port_range, rule) 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("type", rule.Direction)
d.Set("ip_protocol", strings.ToLower(string(rule.IpProtocol))) d.Set("ip_protocol", strings.ToLower(string(rule.IpProtocol)))
d.Set("nic_type", rule.NicType) d.Set("nic_type", rule.NicType)
@ -146,7 +150,7 @@ func resourceAliyunSecurityGroupRuleRead(d *schema.ResourceData, meta interface{
d.Set("priority", rule.Priority) d.Set("priority", rule.Priority)
d.Set("security_group_id", sgId) d.Set("security_group_id", sgId)
//support source and desc by type //support source and desc by type
if GroupRuleDirection(types) == GroupRuleIngress { if GroupRuleDirection(direction) == GroupRuleIngress {
d.Set("cidr_ip", rule.SourceCidrIp) d.Set("cidr_ip", rule.SourceCidrIp)
d.Set("source_security_group_id", rule.SourceGroupId) d.Set("source_security_group_id", rule.SourceGroupId)
d.Set("source_group_owner_account", rule.SourceGroupOwnerAccount) d.Set("source_group_owner_account", rule.SourceGroupOwnerAccount)
@ -161,17 +165,41 @@ func resourceAliyunSecurityGroupRuleRead(d *schema.ResourceData, meta interface{
func resourceAliyunSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{}) error { func resourceAliyunSecurityGroupRuleDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*AliyunClient) 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 { if err != nil {
return err return err
} }
revokeArgs := &ecs.RevokeSecurityGroupArgs{ revokeArgs := &ecs.RevokeSecurityGroupEgressArgs{
AuthorizeSecurityGroupArgs: *args, AuthorizeSecurityGroupEgressArgs: *args,
} }
return client.RevokeSecurityGroup(revokeArgs) return client.RevokeSecurityGroupEgress(revokeArgs)
} }
func checkCidrAndSourceGroupId(cidrIp, sourceGroupId string) error {
if cidrIp == "" && sourceGroupId == "" {
return fmt.Errorf("Either cidr_ip or source_security_group_id is required.")
}
if cidrIp != "" && sourceGroupId != "" {
return fmt.Errorf("You should set only one value of cidr_ip or source_security_group_id.")
}
return nil
}
func buildAliyunSecurityIngressArgs(d *schema.ResourceData, meta interface{}) (*ecs.AuthorizeSecurityGroupArgs, error) { func buildAliyunSecurityIngressArgs(d *schema.ResourceData, meta interface{}) (*ecs.AuthorizeSecurityGroupArgs, error) {
conn := meta.(*AliyunClient).ecsconn conn := meta.(*AliyunClient).ecsconn
@ -199,12 +227,17 @@ func buildAliyunSecurityIngressArgs(d *schema.ResourceData, meta interface{}) (*
args.NicType = ecs.NicType(v) args.NicType = ecs.NicType(v)
} }
if v := d.Get("cidr_ip").(string); v != "" { cidrIp := d.Get("cidr_ip").(string)
args.SourceCidrIp = v sourceGroupId := d.Get("source_security_group_id").(string)
if err := checkCidrAndSourceGroupId(cidrIp, sourceGroupId); err != nil {
return nil, err
}
if cidrIp != "" {
args.SourceCidrIp = cidrIp
} }
if v := d.Get("source_security_group_id").(string); v != "" { if sourceGroupId != "" {
args.SourceGroupId = v args.SourceGroupId = sourceGroupId
} }
if v := d.Get("source_group_owner_account").(string); v != "" { if v := d.Get("source_group_owner_account").(string); v != "" {
@ -255,12 +288,17 @@ func buildAliyunSecurityEgressArgs(d *schema.ResourceData, meta interface{}) (*e
args.NicType = ecs.NicType(v) args.NicType = ecs.NicType(v)
} }
if v := d.Get("cidr_ip").(string); v != "" { cidrIp := d.Get("cidr_ip").(string)
args.DestCidrIp = v sourceGroupId := d.Get("source_security_group_id").(string)
if err := checkCidrAndSourceGroupId(cidrIp, sourceGroupId); err != nil {
return nil, err
}
if cidrIp != "" {
args.DestCidrIp = cidrIp
} }
if v := d.Get("source_security_group_id").(string); v != "" { if sourceGroupId != "" {
args.DestGroupId = v args.DestGroupId = sourceGroupId
} }
if v := d.Get("source_group_owner_account").(string); v != "" { if v := d.Get("source_group_owner_account").(string); v != "" {

View File

@ -7,6 +7,7 @@ import (
"github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"log" "log"
"regexp"
"strings" "strings"
"testing" "testing"
) )
@ -81,6 +82,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) { func TestAccAlicloudSecurityGroupRule_Vpc_Ingress(t *testing.T) {
var pt ecs.PermissionType var pt ecs.PermissionType
@ -114,6 +148,80 @@ 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 TestAccAlicloudSecurityGroupRule_SourceSecurityGroup(t *testing.T) {
var pt ecs.PermissionType
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
// module name
IDRefreshName: "alicloud_security_group_rule.ingress",
Providers: testAccProviders,
CheckDestroy: testAccCheckSecurityGroupRuleDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccSecurityGroupRuleSourceSecurityGroup,
Check: resource.ComposeTestCheckFunc(
testAccCheckSecurityGroupRuleExists(
"alicloud_security_group_rule.ingress", &pt),
resource.TestCheckResourceAttr(
"alicloud_security_group_rule.ingress",
"port_range",
"3306/3306"),
resource.TestMatchResourceAttr(
"alicloud_security_group_rule.ingress",
"source_security_group_id",
regexp.MustCompile("^sg-[a-zA-Z0-9_]+")),
resource.TestCheckResourceAttr(
"alicloud_security_group_rule.ingress",
"cidr_ip",
""),
),
},
},
})
}
func testAccCheckSecurityGroupRuleExists(n string, m *ecs.PermissionType) resource.TestCheckFunc { func testAccCheckSecurityGroupRuleExists(n string, m *ecs.PermissionType) resource.TestCheckFunc {
return func(s *terraform.State) error { return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n] rs, ok := s.RootModule().Resources[n]
@ -128,7 +236,8 @@ func testAccCheckSecurityGroupRuleExists(n string, m *ecs.PermissionType) resour
client := testAccProvider.Meta().(*AliyunClient) client := testAccProvider.Meta().(*AliyunClient)
log.Printf("[WARN]get sg rule %s", rs.Primary.ID) log.Printf("[WARN]get sg rule %s", rs.Primary.ID)
parts := strings.Split(rs.Primary.ID, ":") parts := strings.Split(rs.Primary.ID, ":")
rule, err := client.DescribeSecurityGroupRule(parts[0], parts[1], parts[2], parts[3]) // securityGroupId, direction, nicType, ipProtocol, portRange
rule, err := client.DescribeSecurityGroupRule(parts[0], parts[1], parts[4], parts[2], parts[3])
if err != nil { if err != nil {
return err return err
@ -152,7 +261,7 @@ func testAccCheckSecurityGroupRuleDestroy(s *terraform.State) error {
} }
parts := strings.Split(rs.Primary.ID, ":") parts := strings.Split(rs.Primary.ID, ":")
rule, err := client.DescribeSecurityGroupRule(parts[0], parts[1], parts[2], parts[3]) rule, err := client.DescribeSecurityGroupRule(parts[0], parts[1], parts[4], parts[2], parts[3])
if rule != nil { if rule != nil {
return fmt.Errorf("Error SecurityGroup Rule still exist") return fmt.Errorf("Error SecurityGroup Rule still exist")
@ -210,6 +319,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 = ` const testAccSecurityGroupRuleVpcIngress = `
resource "alicloud_security_group" "foo" { resource "alicloud_security_group" "foo" {
vpc_id = "${alicloud_vpc.vpc.id}" vpc_id = "${alicloud_vpc.vpc.id}"
@ -231,6 +357,22 @@ resource "alicloud_security_group_rule" "ingress" {
cidr_ip = "10.159.6.18/12" 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 = ` const testAccSecurityGroupRuleMultiIngress = `
@ -260,4 +402,27 @@ resource "alicloud_security_group_rule" "ingress2" {
cidr_ip = "127.0.1.18/16" cidr_ip = "127.0.1.18/16"
} }
`
const testAccSecurityGroupRuleSourceSecurityGroup = `
resource "alicloud_security_group" "foo" {
name = "sg_foo"
}
resource "alicloud_security_group" "bar" {
name = "sg_bar"
}
resource "alicloud_security_group_rule" "ingress" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "intranet"
policy = "accept"
port_range = "3306/3306"
priority = 50
security_group_id = "${alicloud_security_group.bar.id}"
source_security_group_id = "${alicloud_security_group.foo.id}"
}
` `

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"errors"
"github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/slb" "github.com/denverdino/aliyungo/slb"
"github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/hashcode"
@ -83,40 +84,124 @@ func resourceAliyunSlb() *schema.Resource {
ValidateFunc: validateSlbListenerBandwidth, ValidateFunc: validateSlbListenerBandwidth,
Required: true, Required: true,
}, },
//http
"scheduler": &schema.Schema{ "scheduler": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
ValidateFunc: validateSlbListenerScheduler, ValidateFunc: validateSlbListenerScheduler,
Optional: true, Optional: true,
Default: "wrr", Default: slb.WRRScheduler,
}, },
//http & https
"sticky_session": &schema.Schema{ "sticky_session": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
ValidateFunc: validateSlbListenerStickySession, ValidateFunc: validateAllowedStringValue([]string{
Optional: true, string(slb.OnFlag),
string(slb.OffFlag)}),
Optional: true,
Default: slb.OffFlag,
}, },
//http & https
"sticky_session_type": &schema.Schema{ "sticky_session_type": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
ValidateFunc: validateSlbListenerStickySessionType, ValidateFunc: validateAllowedStringValue([]string{
string(slb.InsertStickySessionType),
string(slb.ServerStickySessionType)}),
Optional: true,
},
//http & https
"cookie_timeout": &schema.Schema{
Type: schema.TypeInt,
ValidateFunc: validateSlbListenerCookieTimeout,
Optional: true, Optional: true,
}, },
//http & https
"cookie": &schema.Schema{ "cookie": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
ValidateFunc: validateSlbListenerCookie, ValidateFunc: validateSlbListenerCookie,
Optional: true, Optional: true,
}, },
"PersistenceTimeout": &schema.Schema{ //tcp & udp
"persistence_timeout": &schema.Schema{
Type: schema.TypeInt, Type: schema.TypeInt,
ValidateFunc: validateSlbListenerPersistenceTimeout, ValidateFunc: validateSlbListenerPersistenceTimeout,
Optional: true, Optional: true,
Default: 0, Default: 0,
}, },
//http & https
"health_check": &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateAllowedStringValue([]string{
string(slb.OnFlag),
string(slb.OffFlag)}),
Optional: true,
Default: slb.OffFlag,
},
//tcp
"health_check_type": &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateAllowedStringValue([]string{
string(slb.TCPHealthCheckType),
string(slb.HTTPHealthCheckType)}),
Optional: true,
Default: slb.TCPHealthCheckType,
},
//http & https & tcp
"health_check_domain": &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateSlbListenerHealthCheckDomain,
Optional: true,
},
//http & https & tcp
"health_check_uri": &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateSlbListenerHealthCheckUri,
Optional: true,
},
"health_check_connect_port": &schema.Schema{
Type: schema.TypeInt,
ValidateFunc: validateSlbListenerHealthCheckConnectPort,
Optional: true,
},
"healthy_threshold": &schema.Schema{
Type: schema.TypeInt,
ValidateFunc: validateIntegerInRange(1, 10),
Optional: true,
},
"unhealthy_threshold": &schema.Schema{
Type: schema.TypeInt,
ValidateFunc: validateIntegerInRange(1, 10),
Optional: true,
},
"health_check_timeout": &schema.Schema{
Type: schema.TypeInt,
ValidateFunc: validateIntegerInRange(1, 50),
Optional: true,
},
"health_check_interval": &schema.Schema{
Type: schema.TypeInt,
ValidateFunc: validateIntegerInRange(1, 5),
Optional: true,
},
//http & https & tcp
"health_check_http_code": &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validateAllowedSplitStringValue([]string{
string(slb.HTTP_2XX),
string(slb.HTTP_3XX),
string(slb.HTTP_4XX),
string(slb.HTTP_5XX)}, ","),
Optional: true,
},
//https //https
"ssl_certificate_id": &schema.Schema{ "ssl_certificate_id": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
}, },
//https
//"ca_certificate_id": &schema.Schema{
// Type: schema.TypeString,
// Optional: true,
//},
}, },
}, },
Set: resourceAliyunSlbListenerHash, Set: resourceAliyunSlbListenerHash,
@ -349,44 +434,53 @@ func resourceAliyunSlbListenerHash(v interface{}) int {
} }
func createListener(conn *slb.Client, loadBalancerId string, listener *Listener) error { func createListener(conn *slb.Client, loadBalancerId string, listener *Listener) error {
errTypeJudge := func(err error) error {
if err != nil {
if listenerType, ok := err.(*ListenerErr); ok {
if listenerType.ErrType == HealthCheckErrType {
return fmt.Errorf("When the HealthCheck is %s, then related HealthCheck parameter "+
"must have.", slb.OnFlag)
} else if listenerType.ErrType == StickySessionErrType {
return fmt.Errorf("When the StickySession is %s, then StickySessionType parameter "+
"must have.", slb.OnFlag)
} else if listenerType.ErrType == CookieTimeOutErrType {
return fmt.Errorf("When the StickySession is %s and StickySessionType is %s, "+
"then CookieTimeout parameter must have.", slb.OnFlag, slb.InsertStickySessionType)
} else if listenerType.ErrType == CookieErrType {
return fmt.Errorf("When the StickySession is %s and StickySessionType is %s, "+
"then Cookie parameter must have.", slb.OnFlag, slb.ServerStickySessionType)
}
return fmt.Errorf("slb listener check errtype not found.")
}
}
return nil
}
if listener.Protocol == strings.ToLower("tcp") { if listener.Protocol == strings.ToLower("tcp") {
args := &slb.CreateLoadBalancerTCPListenerArgs{
LoadBalancerId: loadBalancerId, args := getTcpListenerArgs(loadBalancerId, listener)
ListenerPort: listener.LoadBalancerPort,
BackendServerPort: listener.InstancePort, if err := conn.CreateLoadBalancerTCPListener(&args); err != nil {
Bandwidth: listener.Bandwidth,
}
if err := conn.CreateLoadBalancerTCPListener(args); err != nil {
return err return err
} }
} } else if listener.Protocol == strings.ToLower("http") {
args, argsErr := getHttpListenerArgs(loadBalancerId, listener)
if listener.Protocol == strings.ToLower("http") { if paramErr := errTypeJudge(argsErr); paramErr != nil {
args := &slb.CreateLoadBalancerHTTPListenerArgs{ return paramErr
LoadBalancerId: loadBalancerId,
ListenerPort: listener.LoadBalancerPort,
BackendServerPort: listener.InstancePort,
Bandwidth: listener.Bandwidth,
StickySession: slb.OffFlag,
HealthCheck: slb.OffFlag,
} }
if err := conn.CreateLoadBalancerHTTPListener(args); err != nil { if err := conn.CreateLoadBalancerHTTPListener(&args); err != nil {
return err return err
} }
} } else if listener.Protocol == strings.ToLower("https") {
listenerType, err := getHttpListenerType(loadBalancerId, listener)
if paramErr := errTypeJudge(err); paramErr != nil {
return paramErr
}
if listener.Protocol == strings.ToLower("https") {
args := &slb.CreateLoadBalancerHTTPSListenerArgs{ args := &slb.CreateLoadBalancerHTTPSListenerArgs{
HTTPListenerType: listenerType,
HTTPListenerType: slb.HTTPListenerType{
LoadBalancerId: loadBalancerId,
ListenerPort: listener.LoadBalancerPort,
BackendServerPort: listener.InstancePort,
Bandwidth: listener.Bandwidth,
StickySession: slb.OffFlag,
HealthCheck: slb.OffFlag,
},
} }
if listener.SSLCertificateId == "" { if listener.SSLCertificateId == "" {
return fmt.Errorf("Server Certificated Id cann't be null") return fmt.Errorf("Server Certificated Id cann't be null")
@ -397,17 +491,10 @@ func createListener(conn *slb.Client, loadBalancerId string, listener *Listener)
if err := conn.CreateLoadBalancerHTTPSListener(args); err != nil { if err := conn.CreateLoadBalancerHTTPSListener(args); err != nil {
return err return err
} }
} } else if listener.Protocol == strings.ToLower("udp") {
args := getUdpListenerArgs(loadBalancerId, listener)
if listener.Protocol == strings.ToLower("udp") { if err := conn.CreateLoadBalancerUDPListener(&args); err != nil {
args := &slb.CreateLoadBalancerUDPListenerArgs{
LoadBalancerId: loadBalancerId,
ListenerPort: listener.LoadBalancerPort,
BackendServerPort: listener.InstancePort,
Bandwidth: listener.Bandwidth,
}
if err := conn.CreateLoadBalancerUDPListener(args); err != nil {
return err return err
} }
} }
@ -418,3 +505,102 @@ func createListener(conn *slb.Client, loadBalancerId string, listener *Listener)
return nil return nil
} }
func getTcpListenerArgs(loadBalancerId string, listener *Listener) slb.CreateLoadBalancerTCPListenerArgs {
args := slb.CreateLoadBalancerTCPListenerArgs{
LoadBalancerId: loadBalancerId,
ListenerPort: listener.LoadBalancerPort,
BackendServerPort: listener.InstancePort,
Bandwidth: listener.Bandwidth,
Scheduler: listener.Scheduler,
PersistenceTimeout: listener.PersistenceTimeout,
HealthCheckType: listener.HealthCheckType,
HealthCheckDomain: listener.HealthCheckDomain,
HealthCheckURI: listener.HealthCheckURI,
HealthCheckConnectPort: listener.HealthCheckConnectPort,
HealthyThreshold: listener.HealthyThreshold,
UnhealthyThreshold: listener.UnhealthyThreshold,
HealthCheckConnectTimeout: listener.HealthCheckTimeout,
HealthCheckInterval: listener.HealthCheckInterval,
HealthCheckHttpCode: listener.HealthCheckHttpCode,
}
return args
}
func getUdpListenerArgs(loadBalancerId string, listener *Listener) slb.CreateLoadBalancerUDPListenerArgs {
args := slb.CreateLoadBalancerUDPListenerArgs{
LoadBalancerId: loadBalancerId,
ListenerPort: listener.LoadBalancerPort,
BackendServerPort: listener.InstancePort,
Bandwidth: listener.Bandwidth,
PersistenceTimeout: listener.PersistenceTimeout,
HealthCheckConnectTimeout: listener.HealthCheckTimeout,
HealthCheckInterval: listener.HealthCheckInterval,
}
return args
}
func getHttpListenerType(loadBalancerId string, listener *Listener) (listenType slb.HTTPListenerType, err error) {
if listener.HealthCheck == slb.OnFlag {
if listener.HealthCheckURI == "" || listener.HealthCheckDomain == "" || listener.HealthCheckConnectPort == 0 ||
listener.HealthyThreshold == 0 || listener.UnhealthyThreshold == 0 || listener.HealthCheckTimeout == 0 ||
listener.HealthCheckHttpCode == "" || listener.HealthCheckInterval == 0 {
errMsg := errors.New("err: HealthCheck empty.")
return listenType, &ListenerErr{HealthCheckErrType, errMsg}
}
}
if listener.StickySession == slb.OnFlag {
if listener.StickySessionType == "" {
errMsg := errors.New("err: stickySession empty.")
return listenType, &ListenerErr{StickySessionErrType, errMsg}
}
if listener.StickySessionType == slb.InsertStickySessionType {
if listener.CookieTimeout == 0 {
errMsg := errors.New("err: cookieTimeout empty.")
return listenType, &ListenerErr{CookieTimeOutErrType, errMsg}
}
} else if listener.StickySessionType == slb.ServerStickySessionType {
if listener.Cookie == "" {
errMsg := errors.New("err: cookie empty.")
return listenType, &ListenerErr{CookieErrType, errMsg}
}
}
}
httpListenertType := slb.HTTPListenerType{
LoadBalancerId: loadBalancerId,
ListenerPort: listener.LoadBalancerPort,
BackendServerPort: listener.InstancePort,
Bandwidth: listener.Bandwidth,
Scheduler: listener.Scheduler,
HealthCheck: listener.HealthCheck,
StickySession: listener.StickySession,
StickySessionType: listener.StickySessionType,
CookieTimeout: listener.CookieTimeout,
Cookie: listener.Cookie,
HealthCheckDomain: listener.HealthCheckDomain,
HealthCheckURI: listener.HealthCheckURI,
HealthCheckConnectPort: listener.HealthCheckConnectPort,
HealthyThreshold: listener.HealthyThreshold,
UnhealthyThreshold: listener.UnhealthyThreshold,
HealthCheckTimeout: listener.HealthCheckTimeout,
HealthCheckInterval: listener.HealthCheckInterval,
HealthCheckHttpCode: listener.HealthCheckHttpCode,
}
return httpListenertType, err
}
func getHttpListenerArgs(loadBalancerId string, listener *Listener) (listenType slb.CreateLoadBalancerHTTPListenerArgs, err error) {
httpListenerType, err := getHttpListenerType(loadBalancerId, listener)
if err != nil {
return listenType, err
}
httpArgs := slb.CreateLoadBalancerHTTPListenerArgs(httpListenerType)
return httpArgs, err
}

View File

@ -79,9 +79,30 @@ resource "alicloud_security_group" "foo" {
description = "foo" description = "foo"
} }
resource "alicloud_security_group_rule" "http-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "internet"
policy = "accept"
port_range = "80/80"
priority = 1
security_group_id = "${alicloud_security_group.foo.id}"
cidr_ip = "0.0.0.0/0"
}
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.foo.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-b"
image_id = "ubuntu_140405_64_40G_cloudinit_20161115.vhd" image_id = "ubuntu_140405_64_40G_cloudinit_20161115.vhd"
# series II # series II

View File

@ -85,7 +85,7 @@ func TestAccAlicloudSlb_listener(t *testing.T) {
testListener := func() resource.TestCheckFunc { testListener := func() resource.TestCheckFunc {
return func(*terraform.State) error { return func(*terraform.State) error {
listenerPorts := slb.ListenerPorts.ListenerPort[0] listenerPorts := slb.ListenerPorts.ListenerPort[0]
if listenerPorts != 161 { if listenerPorts != 2001 {
return fmt.Errorf("bad loadbalancer listener: %#v", listenerPorts) return fmt.Errorf("bad loadbalancer listener: %#v", listenerPorts)
} }
@ -260,21 +260,49 @@ resource "alicloud_slb" "listener" {
"lb_port" = "21" "lb_port" = "21"
"lb_protocol" = "tcp" "lb_protocol" = "tcp"
"bandwidth" = 1 "bandwidth" = 1
"persistence_timeout" = 500
"health_check_type" = "http"
},{ },{
"instance_port" = "8000" "instance_port" = "8000"
"lb_port" = "80" "lb_port" = "80"
"lb_protocol" = "http" "lb_protocol" = "http"
"sticky_session" = "on"
"sticky_session_type" = "insert"
"cookie_timeout" = 800
"bandwidth" = 1 "bandwidth" = 1
},{ },{
"instance_port" = "1611" "instance_port" = "8001"
"lb_port" = "161" "lb_port" = "81"
"lb_protocol" = "http"
"sticky_session" = "on"
"sticky_session_type" = "server"
"cookie" = "testslblistenercookie"
"cookie_timeout" = 1800
"health_check" = "on"
"health_check_domain" = "$_ip"
"health_check_uri" = "/console"
"health_check_connect_port" = 20
"healthy_threshold" = 8
"unhealthy_threshold" = 8
"health_check_timeout" = 8
"health_check_interval" = 4
"health_check_http_code" = "http_2xx"
"bandwidth" = 1
},{
"instance_port" = "2001"
"lb_port" = "2001"
"lb_protocol" = "udp" "lb_protocol" = "udp"
"bandwidth" = 1 "bandwidth" = 1
"persistence_timeout" = 700
}] }]
} }
` `
const testAccSlb4Vpc = ` const testAccSlb4Vpc = `
data "alicloud_zones" "default" {
"available_resource_creation"= "VSwitch"
}
resource "alicloud_vpc" "foo" { resource "alicloud_vpc" "foo" {
name = "tf_test_foo" name = "tf_test_foo"
cidr_block = "172.16.0.0/12" cidr_block = "172.16.0.0/12"
@ -283,7 +311,7 @@ resource "alicloud_vpc" "foo" {
resource "alicloud_vswitch" "foo" { resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}" vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "172.16.0.0/21" 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" { resource "alicloud_slb" "vpc" {

View File

@ -124,6 +124,10 @@ func testAccCheckRouteEntryDestroy(s *terraform.State) error {
} }
const testAccRouteEntryConfig = ` const testAccRouteEntryConfig = `
data "alicloud_zones" "default" {
"available_resource_creation"= "VSwitch"
}
resource "alicloud_vpc" "foo" { resource "alicloud_vpc" "foo" {
name = "tf_test_foo" name = "tf_test_foo"
cidr_block = "10.1.0.0/21" cidr_block = "10.1.0.0/21"
@ -132,7 +136,7 @@ resource "alicloud_vpc" "foo" {
resource "alicloud_vswitch" "foo" { resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}" vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "10.1.1.0/24" cidr_block = "10.1.1.0/24"
availability_zone = "cn-beijing-c" availability_zone = "${data.alicloud_zones.default.zones.0.id}"
} }
resource "alicloud_route_entry" "foo" { resource "alicloud_route_entry" "foo" {
@ -162,7 +166,6 @@ resource "alicloud_security_group_rule" "ingress" {
resource "alicloud_instance" "foo" { resource "alicloud_instance" "foo" {
# cn-beijing # cn-beijing
availability_zone = "cn-beijing-c"
security_groups = ["${alicloud_security_group.tf_test_foo.id}"] security_groups = ["${alicloud_security_group.tf_test_foo.id}"]
vswitch_id = "${alicloud_vswitch.foo.id}" vswitch_id = "${alicloud_vswitch.foo.id}"

View File

@ -92,6 +92,10 @@ func testAccCheckVswitchDestroy(s *terraform.State) error {
} }
const testAccVswitchConfig = ` const testAccVswitchConfig = `
data "alicloud_zones" "default" {
"available_resource_creation"= "VSwitch"
}
resource "alicloud_vpc" "foo" { resource "alicloud_vpc" "foo" {
name = "tf_test_foo" name = "tf_test_foo"
cidr_block = "172.16.0.0/12" cidr_block = "172.16.0.0/12"
@ -100,6 +104,6 @@ resource "alicloud_vpc" "foo" {
resource "alicloud_vswitch" "foo" { resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}" vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "172.16.0.0/21" cidr_block = "172.16.0.0/21"
availability_zone = "cn-beijing-b" availability_zone = "${data.alicloud_zones.default.zones.0.id}"
} }
` `

View File

@ -84,6 +84,24 @@ func (client *AliyunClient) DescribeZone(zoneID string) (*ecs.ZoneType, error) {
return zone, nil return zone, nil
} }
// return multiIZ list of current region
func (client *AliyunClient) DescribeMultiIZByRegion() (izs []string, err error) {
resp, err := client.rdsconn.DescribeRegions()
if err != nil {
return nil, fmt.Errorf("error to list regions not found")
}
regions := resp.Regions.RDSRegion
zoneIds := []string{}
for _, r := range regions {
if r.RegionId == string(client.Region) && strings.Contains(r.ZoneId, MULTI_IZ_SYMBOL) {
zoneIds = append(zoneIds, r.ZoneId)
}
}
return zoneIds, nil
}
func (client *AliyunClient) QueryInstancesByIds(ids []string) (instances []ecs.InstanceAttributesType, err error) { func (client *AliyunClient) QueryInstancesByIds(ids []string) (instances []ecs.InstanceAttributesType, err error) {
idsStr, jerr := json.Marshal(ids) idsStr, jerr := json.Marshal(ids)
if jerr != nil { if jerr != nil {
@ -119,6 +137,23 @@ func (client *AliyunClient) QueryInstancesById(id string) (instance *ecs.Instanc
return &instances[0], nil return &instances[0], nil
} }
func (client *AliyunClient) QueryInstanceSystemDisk(id string) (disk *ecs.DiskItemType, err error) {
args := ecs.DescribeDisksArgs{
RegionId: client.Region,
InstanceId: string(id),
DiskType: ecs.DiskTypeAllSystem,
}
disks, _, err := client.ecsconn.DescribeDisks(&args)
if err != nil {
return nil, err
}
if len(disks) == 0 {
return nil, common.GetClientErrorFromString(SystemDiskNotFound)
}
return &disks[0], nil
}
// ResourceAvailable check resource available for zone // ResourceAvailable check resource available for zone
func (client *AliyunClient) ResourceAvailable(zone *ecs.ZoneType, resourceType ecs.ResourceType) error { func (client *AliyunClient) ResourceAvailable(zone *ecs.ZoneType, resourceType ecs.ResourceType) error {
available := false available := false
@ -186,15 +221,26 @@ func (client *AliyunClient) DescribeSecurity(securityGroupId string) (*ecs.Descr
return client.ecsconn.DescribeSecurityGroupAttribute(args) return client.ecsconn.DescribeSecurityGroupAttribute(args)
} }
func (client *AliyunClient) DescribeSecurityGroupRule(securityGroupId, types, ip_protocol, port_range string) (*ecs.PermissionType, error) { func (client *AliyunClient) DescribeSecurityByAttr(securityGroupId, direction, nicType string) (*ecs.DescribeSecurityGroupAttributeResponse, error) {
sg, err := client.DescribeSecurity(securityGroupId) args := &ecs.DescribeSecurityGroupAttributeArgs{
RegionId: client.Region,
SecurityGroupId: securityGroupId,
Direction: direction,
NicType: ecs.NicType(nicType),
}
return client.ecsconn.DescribeSecurityGroupAttribute(args)
}
func (client *AliyunClient) DescribeSecurityGroupRule(securityGroupId, direction, nicType, ipProtocol, portRange string) (*ecs.PermissionType, error) {
sg, err := client.DescribeSecurityByAttr(securityGroupId, direction, nicType)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, p := range sg.Permissions.Permission { for _, p := range sg.Permissions.Permission {
if strings.ToLower(string(p.IpProtocol)) == ip_protocol && p.PortRange == port_range { if strings.ToLower(string(p.IpProtocol)) == ipProtocol && p.PortRange == portRange {
return &p, nil return &p, nil
} }
} }
@ -203,6 +249,11 @@ func (client *AliyunClient) DescribeSecurityGroupRule(securityGroupId, types, ip
} }
func (client *AliyunClient) RevokeSecurityGroup(args *ecs.RevokeSecurityGroupArgs) error { 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) 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)
}

View File

@ -0,0 +1,278 @@
package alicloud
import (
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/rds"
"strings"
)
// when getInstance is empty, then throw InstanceNotfound error
func (client *AliyunClient) DescribeDBInstanceById(id string) (instance *rds.DBInstanceAttribute, err error) {
arrtArgs := rds.DescribeDBInstancesArgs{
DBInstanceId: id,
}
resp, err := client.rdsconn.DescribeDBInstanceAttribute(&arrtArgs)
if err != nil {
return nil, err
}
attr := resp.Items.DBInstanceAttribute
if len(attr) <= 0 {
return nil, common.GetClientErrorFromString(InstanceNotfound)
}
return &attr[0], nil
}
func (client *AliyunClient) CreateAccountByInfo(instanceId, username, pwd string) error {
conn := client.rdsconn
args := rds.CreateAccountArgs{
DBInstanceId: instanceId,
AccountName: username,
AccountPassword: pwd,
}
if _, err := conn.CreateAccount(&args); err != nil {
return err
}
if err := conn.WaitForAccount(instanceId, username, rds.Available, 200); err != nil {
return err
}
return nil
}
func (client *AliyunClient) CreateDatabaseByInfo(instanceId, dbName, charset, desp string) error {
conn := client.rdsconn
args := rds.CreateDatabaseArgs{
DBInstanceId: instanceId,
DBName: dbName,
CharacterSetName: charset,
DBDescription: desp,
}
_, err := conn.CreateDatabase(&args)
return err
}
func (client *AliyunClient) DescribeDatabaseByName(instanceId, dbName string) (ds []rds.Database, err error) {
conn := client.rdsconn
args := rds.DescribeDatabasesArgs{
DBInstanceId: instanceId,
DBName: dbName,
}
resp, err := conn.DescribeDatabases(&args)
if err != nil {
return nil, err
}
return resp.Databases.Database, nil
}
func (client *AliyunClient) GrantDBPrivilege2Account(instanceId, username, dbName string) error {
conn := client.rdsconn
pargs := rds.GrantAccountPrivilegeArgs{
DBInstanceId: instanceId,
AccountName: username,
DBName: dbName,
AccountPrivilege: rds.ReadWrite,
}
if _, err := conn.GrantAccountPrivilege(&pargs); err != nil {
return err
}
if err := conn.WaitForAccountPrivilege(instanceId, username, dbName, rds.ReadWrite, 200); err != nil {
return err
}
return nil
}
func (client *AliyunClient) AllocateDBPublicConnection(instanceId, port string) error {
conn := client.rdsconn
args := rds.AllocateInstancePublicConnectionArgs{
DBInstanceId: instanceId,
ConnectionStringPrefix: instanceId + "o",
Port: port,
}
if _, err := conn.AllocateInstancePublicConnection(&args); err != nil {
return err
}
if err := conn.WaitForPublicConnection(instanceId, 600); err != nil {
return err
}
return nil
}
func (client *AliyunClient) ConfigDBBackup(instanceId, backupTime, backupPeriod string, retentionPeriod int) error {
bargs := rds.BackupPolicy{
PreferredBackupTime: backupTime,
PreferredBackupPeriod: backupPeriod,
BackupRetentionPeriod: retentionPeriod,
}
args := rds.ModifyBackupPolicyArgs{
DBInstanceId: instanceId,
BackupPolicy: bargs,
}
if _, err := client.rdsconn.ModifyBackupPolicy(&args); err != nil {
return err
}
if err := client.rdsconn.WaitForInstance(instanceId, rds.Running, 600); err != nil {
return err
}
return nil
}
func (client *AliyunClient) ModifyDBSecurityIps(instanceId, ips string) error {
sargs := rds.DBInstanceIPArray{
SecurityIps: ips,
}
args := rds.ModifySecurityIpsArgs{
DBInstanceId: instanceId,
DBInstanceIPArray: sargs,
}
if _, err := client.rdsconn.ModifySecurityIps(&args); err != nil {
return err
}
if err := client.rdsconn.WaitForInstance(instanceId, rds.Running, 600); err != nil {
return err
}
return nil
}
func (client *AliyunClient) DescribeDBSecurityIps(instanceId string) (ips []rds.DBInstanceIPList, err error) {
args := rds.DescribeDBInstanceIPsArgs{
DBInstanceId: instanceId,
}
resp, err := client.rdsconn.DescribeDBInstanceIPs(&args)
if err != nil {
return nil, err
}
return resp.Items.DBInstanceIPArray, nil
}
func (client *AliyunClient) GetSecurityIps(instanceId string) ([]string, error) {
arr, err := client.DescribeDBSecurityIps(instanceId)
if err != nil {
return nil, err
}
ips := ""
for i, ip := range arr {
if i == 0 {
ips += ip.SecurityIPList
} else {
ips += COMMA_SEPARATED + ip.SecurityIPList
}
}
return strings.Split(ips, COMMA_SEPARATED), nil
}
func (client *AliyunClient) ModifyDBClassStorage(instanceId, class, storage string) error {
conn := client.rdsconn
args := rds.ModifyDBInstanceSpecArgs{
DBInstanceId: instanceId,
PayType: rds.Postpaid,
DBInstanceClass: class,
DBInstanceStorage: storage,
}
if _, err := conn.ModifyDBInstanceSpec(&args); err != nil {
return err
}
if err := conn.WaitForInstance(instanceId, rds.Running, 600); err != nil {
return err
}
return nil
}
// turn period to TimeType
func TransformPeriod2Time(period int, chargeType string) (ut int, tt common.TimeType) {
if chargeType == string(rds.Postpaid) {
return 1, common.Day
}
if period >= 1 && period <= 9 {
return period, common.Month
}
if period == 12 {
return 1, common.Year
}
if period == 24 {
return 2, common.Year
}
return 0, common.Day
}
// turn TimeType to Period
func TransformTime2Period(ut int, tt common.TimeType) (period int) {
if tt == common.Year {
return 12 * ut
}
return ut
}
// Flattens an array of databases into a []map[string]interface{}
func flattenDatabaseMappings(list []rds.Database) []map[string]interface{} {
result := make([]map[string]interface{}, 0, len(list))
for _, i := range list {
l := map[string]interface{}{
"db_name": i.DBName,
"character_set_name": i.CharacterSetName,
"db_description": i.DBDescription,
}
result = append(result, l)
}
return result
}
func flattenDBBackup(list []rds.BackupPolicy) []map[string]interface{} {
result := make([]map[string]interface{}, 0, len(list))
for _, i := range list {
l := map[string]interface{}{
"preferred_backup_period": i.PreferredBackupPeriod,
"preferred_backup_time": i.PreferredBackupTime,
"backup_retention_period": i.LogBackupRetentionPeriod,
}
result = append(result, l)
}
return result
}
func flattenDBSecurityIPs(list []rds.DBInstanceIPList) []map[string]interface{} {
result := make([]map[string]interface{}, 0, len(list))
for _, i := range list {
l := map[string]interface{}{
"security_ips": i.SecurityIPList,
}
result = append(result, l)
}
return result
}
// Flattens an array of databases connection into a []map[string]interface{}
func flattenDBConnections(list []rds.DBInstanceNetInfo) []map[string]interface{} {
result := make([]map[string]interface{}, 0, len(list))
for _, i := range list {
l := map[string]interface{}{
"connection_string": i.ConnectionString,
"ip_type": i.IPType,
"ip_address": i.IPAddress,
}
result = append(result, l)
}
return result
}

View File

@ -24,14 +24,14 @@ func (client *AliyunClient) DescribeEipAddress(allocationId string) (*ecs.EipAdd
return &eips[0], nil return &eips[0], nil
} }
func (client *AliyunClient) DescribeNatGateway(natGatewayId string) (*NatGatewaySetType, error) { func (client *AliyunClient) DescribeNatGateway(natGatewayId string) (*ecs.NatGatewaySetType, error) {
args := &DescribeNatGatewaysArgs{ args := &ecs.DescribeNatGatewaysArgs{
RegionId: client.Region, RegionId: client.Region,
NatGatewayId: natGatewayId, NatGatewayId: natGatewayId,
} }
natGateways, _, err := DescribeNatGateways(client.ecsconn, args) natGateways, _, err := client.vpcconn.DescribeNatGateways(args)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -132,3 +132,23 @@ func (client *AliyunClient) QueryRouteEntry(routeTableId, cidrBlock, nextHopType
} }
return nil, nil return nil, nil
} }
func (client *AliyunClient) GetVpcIdByVSwitchId(vswitchId string) (vpcId string, err error) {
vs, _, err := client.ecsconn.DescribeVpcs(&ecs.DescribeVpcsArgs{
RegionId: client.Region,
})
if err != nil {
return "", err
}
for _, v := range vs {
for _, sw := range v.VSwitchIds.VSwitchId {
if sw == vswitchId {
return v.VpcId, nil
}
}
}
return "", &common.Error{ErrorResponse: common.ErrorResponse{Message: Notfound}}
}

View File

@ -2,17 +2,27 @@ package alicloud
import ( import (
"fmt" "fmt"
"regexp" "net"
"strconv"
"strings" "strings"
"github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs" "github.com/denverdino/aliyungo/ecs"
"github.com/hashicorp/terraform/helper/validation" "github.com/denverdino/aliyungo/slb"
"github.com/hashicorp/terraform/helper/schema"
"regexp"
) )
// common // common
func validateInstancePort(v interface{}, k string) (ws []string, errors []error) { func validateInstancePort(v interface{}, k string) (ws []string, errors []error) {
return validation.IntBetween(1, 65535)(v, k) value := v.(int)
if value < 1 || value > 65535 {
errors = append(errors, fmt.Errorf(
"%q must be a valid instance port between 1 and 65535",
k))
return
}
return
} }
func validateInstanceProtocol(v interface{}, k string) (ws []string, errors []error) { func validateInstanceProtocol(v interface{}, k string) (ws []string, errors []error) {
@ -28,11 +38,12 @@ func validateInstanceProtocol(v interface{}, k string) (ws []string, errors []er
// ecs // ecs
func validateDiskCategory(v interface{}, k string) (ws []string, errors []error) { func validateDiskCategory(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{ category := ecs.DiskCategory(v.(string))
string(ecs.DiskCategoryCloud), if category != ecs.DiskCategoryCloud && category != ecs.DiskCategoryCloudEfficiency && category != ecs.DiskCategoryCloudSSD {
string(ecs.DiskCategoryCloudEfficiency), errors = append(errors, fmt.Errorf("%s must be one of %s %s %s", k, ecs.DiskCategoryCloud, ecs.DiskCategoryCloudEfficiency, ecs.DiskCategoryCloudSSD))
string(ecs.DiskCategoryCloudSSD), }
}, false)(v, k)
return
} }
func validateInstanceName(v interface{}, k string) (ws []string, errors []error) { func validateInstanceName(v interface{}, k string) (ws []string, errors []error) {
@ -49,7 +60,12 @@ func validateInstanceName(v interface{}, k string) (ws []string, errors []error)
} }
func validateInstanceDescription(v interface{}, k string) (ws []string, errors []error) { func validateInstanceDescription(v interface{}, k string) (ws []string, errors []error) {
return validation.StringLenBetween(2, 256)(v, k) value := v.(string)
if len(value) < 2 || len(value) > 256 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 256 characters", k))
}
return
} }
func validateDiskName(v interface{}, k string) (ws []string, errors []error) { func validateDiskName(v interface{}, k string) (ws []string, errors []error) {
@ -71,7 +87,12 @@ func validateDiskName(v interface{}, k string) (ws []string, errors []error) {
} }
func validateDiskDescription(v interface{}, k string) (ws []string, errors []error) { func validateDiskDescription(v interface{}, k string) (ws []string, errors []error) {
return validation.StringLenBetween(2, 128)(v, k) value := v.(string)
if len(value) < 2 || len(value) > 256 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 256 characters", k))
}
return
} }
//security group //security group
@ -89,114 +110,225 @@ func validateSecurityGroupName(v interface{}, k string) (ws []string, errors []e
} }
func validateSecurityGroupDescription(v interface{}, k string) (ws []string, errors []error) { func validateSecurityGroupDescription(v interface{}, k string) (ws []string, errors []error) {
return validation.StringLenBetween(2, 256)(v, k) value := v.(string)
if len(value) < 2 || len(value) > 256 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 256 characters", k))
}
return
} }
func validateSecurityRuleType(v interface{}, k string) (ws []string, errors []error) { func validateSecurityRuleType(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{ rt := GroupRuleDirection(v.(string))
string(GroupRuleIngress), if rt != GroupRuleIngress && rt != GroupRuleEgress {
string(GroupRuleEgress), errors = append(errors, fmt.Errorf("%s must be one of %s %s", k, GroupRuleIngress, GroupRuleEgress))
}, false)(v, k) }
return
} }
func validateSecurityRuleIpProtocol(v interface{}, k string) (ws []string, errors []error) { func validateSecurityRuleIpProtocol(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{ pt := GroupRuleIpProtocol(v.(string))
string(GroupRuleTcp), if pt != GroupRuleTcp && pt != GroupRuleUdp && pt != GroupRuleIcmp && pt != GroupRuleGre && pt != GroupRuleAll {
string(GroupRuleUdp), errors = append(errors, fmt.Errorf("%s must be one of %s %s %s %s %s", k,
string(GroupRuleIcmp), GroupRuleTcp, GroupRuleUdp, GroupRuleIcmp, GroupRuleGre, GroupRuleAll))
string(GroupRuleGre), }
string(GroupRuleAll),
}, false)(v, k) return
} }
func validateSecurityRuleNicType(v interface{}, k string) (ws []string, errors []error) { func validateSecurityRuleNicType(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{ pt := GroupRuleNicType(v.(string))
string(GroupRuleInternet), if pt != GroupRuleInternet && pt != GroupRuleIntranet {
string(GroupRuleIntranet), errors = append(errors, fmt.Errorf("%s must be one of %s %s", k, GroupRuleInternet, GroupRuleIntranet))
}, false)(v, k) }
return
} }
func validateSecurityRulePolicy(v interface{}, k string) (ws []string, errors []error) { func validateSecurityRulePolicy(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{ pt := GroupRulePolicy(v.(string))
string(GroupRulePolicyAccept), if pt != GroupRulePolicyAccept && pt != GroupRulePolicyDrop {
string(GroupRulePolicyDrop), errors = append(errors, fmt.Errorf("%s must be one of %s %s", k, GroupRulePolicyAccept, GroupRulePolicyDrop))
}, false)(v, k) }
return
} }
func validateSecurityPriority(v interface{}, k string) (ws []string, errors []error) { func validateSecurityPriority(v interface{}, k string) (ws []string, errors []error) {
return validation.IntBetween(1, 100)(v, k) value := v.(int)
if value < 1 || value > 100 {
errors = append(errors, fmt.Errorf(
"%q must be a valid authorization policy priority between 1 and 100",
k))
return
}
return
} }
// validateCIDRNetworkAddress ensures that the string value is a valid CIDR that // validateCIDRNetworkAddress ensures that the string value is a valid CIDR that
// represents a network address - it adds an error otherwise // represents a network address - it adds an error otherwise
func validateCIDRNetworkAddress(v interface{}, k string) (ws []string, errors []error) { func validateCIDRNetworkAddress(v interface{}, k string) (ws []string, errors []error) {
return validation.CIDRNetwork(0, 32)(v, k) value := v.(string)
_, ipnet, err := net.ParseCIDR(value)
if err != nil {
errors = append(errors, fmt.Errorf(
"%q must contain a valid CIDR, got error parsing: %s", k, err))
return
}
if ipnet == nil || value != ipnet.String() {
errors = append(errors, fmt.Errorf(
"%q must contain a valid network CIDR, expected %q, got %q",
k, ipnet, value))
}
return
} }
func validateRouteEntryNextHopType(v interface{}, k string) (ws []string, errors []error) { func validateRouteEntryNextHopType(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{ nht := ecs.NextHopType(v.(string))
string(ecs.NextHopIntance), if nht != ecs.NextHopIntance && nht != ecs.NextHopTunnel {
string(ecs.NextHopTunnel), errors = append(errors, fmt.Errorf("%s must be one of %s %s", k,
}, false)(v, k) ecs.NextHopIntance, ecs.NextHopTunnel))
}
return
} }
func validateSwitchCIDRNetworkAddress(v interface{}, k string) (ws []string, errors []error) { func validateSwitchCIDRNetworkAddress(v interface{}, k string) (ws []string, errors []error) {
return validation.CIDRNetwork(16, 29)(v, k) value := v.(string)
_, ipnet, err := net.ParseCIDR(value)
if err != nil {
errors = append(errors, fmt.Errorf(
"%q must contain a valid CIDR, got error parsing: %s", k, err))
return
}
if ipnet == nil || value != ipnet.String() {
errors = append(errors, fmt.Errorf(
"%q must contain a valid network CIDR, expected %q, got %q",
k, ipnet, value))
return
}
mark, _ := strconv.Atoi(strings.Split(ipnet.String(), "/")[1])
if mark < 16 || mark > 29 {
errors = append(errors, fmt.Errorf(
"%q must contain a network CIDR which mark between 16 and 29",
k))
}
return
} }
// validateIoOptimized ensures that the string value is a valid IoOptimized that // validateIoOptimized ensures that the string value is a valid IoOptimized that
// represents a IoOptimized - it adds an error otherwise // represents a IoOptimized - it adds an error otherwise
func validateIoOptimized(v interface{}, k string) (ws []string, errors []error) { func validateIoOptimized(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{ if value := v.(string); value != "" {
"", ioOptimized := ecs.IoOptimized(value)
string(ecs.IoOptimizedNone), if ioOptimized != ecs.IoOptimizedNone &&
string(ecs.IoOptimizedOptimized), ioOptimized != ecs.IoOptimizedOptimized {
}, false)(v, k) errors = append(errors, fmt.Errorf(
"%q must contain a valid IoOptimized, expected %s or %s, got %q",
k, ecs.IoOptimizedNone, ecs.IoOptimizedOptimized, ioOptimized))
}
}
return
} }
// validateInstanceNetworkType ensures that the string value is a classic or vpc // validateInstanceNetworkType ensures that the string value is a classic or vpc
func validateInstanceNetworkType(v interface{}, k string) (ws []string, errors []error) { func validateInstanceNetworkType(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{ if value := v.(string); value != "" {
"", network := InstanceNetWork(value)
string(ClassicNet), if network != ClassicNet &&
string(VpcNet), network != VpcNet {
}, false)(v, k) errors = append(errors, fmt.Errorf(
"%q must contain a valid InstanceNetworkType, expected %s or %s, go %q",
k, ClassicNet, VpcNet, network))
}
}
return
} }
func validateInstanceChargeType(v interface{}, k string) (ws []string, errors []error) { func validateInstanceChargeType(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{ if value := v.(string); value != "" {
"", chargeType := common.InstanceChargeType(value)
string(common.PrePaid), if chargeType != common.PrePaid &&
string(common.PostPaid), chargeType != common.PostPaid {
}, false)(v, k) errors = append(errors, fmt.Errorf(
"%q must contain a valid InstanceChargeType, expected %s or %s, got %q",
k, common.PrePaid, common.PostPaid, chargeType))
}
}
return
} }
func validateInternetChargeType(v interface{}, k string) (ws []string, errors []error) { func validateInternetChargeType(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{ if value := v.(string); value != "" {
"", chargeType := common.InternetChargeType(value)
string(common.PayByBandwidth), if chargeType != common.PayByBandwidth &&
string(common.PayByTraffic), chargeType != common.PayByTraffic {
}, false)(v, k) errors = append(errors, fmt.Errorf(
"%q must contain a valid InstanceChargeType, expected %s or %s, got %q",
k, common.PayByBandwidth, common.PayByTraffic, chargeType))
}
}
return
} }
func validateInternetMaxBandWidthOut(v interface{}, k string) (ws []string, errors []error) { func validateInternetMaxBandWidthOut(v interface{}, k string) (ws []string, errors []error) {
return validation.IntBetween(1, 100)(v, k) value := v.(int)
if value < 1 || value > 100 {
errors = append(errors, fmt.Errorf(
"%q must be a valid internet bandwidth out between 1 and 1000",
k))
return
}
return
} }
// SLB // SLB
func validateSlbName(v interface{}, k string) (ws []string, errors []error) { func validateSlbName(v interface{}, k string) (ws []string, errors []error) {
return validation.StringLenBetween(0, 80)(v, k) if value := v.(string); value != "" {
if len(value) < 1 || len(value) > 80 {
errors = append(errors, fmt.Errorf(
"%q must be a valid load balancer name characters between 1 and 80",
k))
return
}
}
return
} }
func validateSlbInternetChargeType(v interface{}, k string) (ws []string, errors []error) { func validateSlbInternetChargeType(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{ if value := v.(string); value != "" {
"paybybandwidth", chargeType := common.InternetChargeType(value)
"paybytraffic",
}, false)(v, k) if chargeType != "paybybandwidth" &&
chargeType != "paybytraffic" {
errors = append(errors, fmt.Errorf(
"%q must contain a valid InstanceChargeType, expected %s or %s, got %q",
k, "paybybandwidth", "paybytraffic", value))
}
}
return
} }
func validateSlbBandwidth(v interface{}, k string) (ws []string, errors []error) { func validateSlbBandwidth(v interface{}, k string) (ws []string, errors []error) {
return validation.IntBetween(1, 1000)(v, k) value := v.(int)
if value < 1 || value > 1000 {
errors = append(errors, fmt.Errorf(
"%q must be a valid load balancer bandwidth between 1 and 1000",
k))
return
}
return
} }
func validateSlbListenerBandwidth(v interface{}, k string) (ws []string, errors []error) { func validateSlbListenerBandwidth(v interface{}, k string) (ws []string, errors []error) {
@ -211,23 +343,180 @@ func validateSlbListenerBandwidth(v interface{}, k string) (ws []string, errors
} }
func validateSlbListenerScheduler(v interface{}, k string) (ws []string, errors []error) { func validateSlbListenerScheduler(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{"wrr", "wlc"}, false)(v, k) if value := v.(string); value != "" {
} scheduler := slb.SchedulerType(value)
func validateSlbListenerStickySession(v interface{}, k string) (ws []string, errors []error) { if scheduler != "wrr" && scheduler != "wlc" {
return validation.StringInSlice([]string{"", "on", "off"}, false)(v, k) errors = append(errors, fmt.Errorf(
} "%q must contain a valid SchedulerType, expected %s or %s, got %q",
k, "wrr", "wlc", value))
}
}
func validateSlbListenerStickySessionType(v interface{}, k string) (ws []string, errors []error) { return
return validation.StringInSlice([]string{"", "insert", "server"}, false)(v, k)
} }
func validateSlbListenerCookie(v interface{}, k string) (ws []string, errors []error) { func validateSlbListenerCookie(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{"", "insert", "server"}, false)(v, k) if value := v.(string); value != "" {
if len(value) < 1 || len(value) > 200 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 200 characters", k))
}
}
return
}
func validateSlbListenerCookieTimeout(v interface{}, k string) (ws []string, errors []error) {
value := v.(int)
if value < 0 || value > 86400 {
errors = append(errors, fmt.Errorf(
"%q must be a valid load balancer cookie timeout between 0 and 86400",
k))
return
}
return
} }
func validateSlbListenerPersistenceTimeout(v interface{}, k string) (ws []string, errors []error) { func validateSlbListenerPersistenceTimeout(v interface{}, k string) (ws []string, errors []error) {
return validation.IntBetween(0, 86400)(v, k) value := v.(int)
if value < 0 || value > 3600 {
errors = append(errors, fmt.Errorf(
"%q must be a valid load balancer persistence timeout between 0 and 86400",
k))
return
}
return
}
func validateSlbListenerHealthCheckDomain(v interface{}, k string) (ws []string, errors []error) {
if value := v.(string); value != "" {
//the len add "$_ip",so to max is 84
if len(value) < 1 || len(value) > 84 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 84 characters", k))
}
}
return
}
func validateSlbListenerHealthCheckUri(v interface{}, k string) (ws []string, errors []error) {
if value := v.(string); value != "" {
if len(value) < 1 || len(value) > 80 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 80 characters", k))
}
}
return
}
func validateSlbListenerHealthCheckConnectPort(v interface{}, k string) (ws []string, errors []error) {
value := v.(int)
if value < 1 || value > 65535 {
if value != -520 {
errors = append(errors, fmt.Errorf(
"%q must be a valid load balancer health check connect port between 1 and 65535 or -520",
k))
return
}
}
return
}
func validateDBBackupPeriod(v interface{}, k string) (ws []string, errors []error) {
days := []string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}
value := v.(string)
exist := false
for _, d := range days {
if value == d {
exist = true
break
}
}
if !exist {
errors = append(errors, fmt.Errorf(
"%q must contain a valid backup period value should in array %#v, got %q",
k, days, value))
}
return
}
func validateAllowedStringValue(ss []string) schema.SchemaValidateFunc {
return func(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
existed := false
for _, s := range ss {
if s == value {
existed = true
break
}
}
if !existed {
errors = append(errors, fmt.Errorf(
"%q must contain a valid string value should in array %#v, got %q",
k, ss, value))
}
return
}
}
func validateAllowedSplitStringValue(ss []string, splitStr string) schema.SchemaValidateFunc {
return func(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
existed := false
tsList := strings.Split(value, splitStr)
for _, ts := range tsList {
existed = false
for _, s := range ss {
if ts == s {
existed = true
break
}
}
}
if !existed {
errors = append(errors, fmt.Errorf(
"%q must contain a valid string value should in %#v, got %q",
k, ss, value))
}
return
}
}
func validateAllowedIntValue(is []int) schema.SchemaValidateFunc {
return func(v interface{}, k string) (ws []string, errors []error) {
value := v.(int)
existed := false
for _, i := range is {
if i == value {
existed = true
break
}
}
if !existed {
errors = append(errors, fmt.Errorf(
"%q must contain a valid int value should in array %#v, got %q",
k, is, value))
}
return
}
}
func validateIntegerInRange(min, max int) schema.SchemaValidateFunc {
return func(v interface{}, k string) (ws []string, errors []error) {
value := v.(int)
if value < min {
errors = append(errors, fmt.Errorf(
"%q cannot be lower than %d: %d", k, min, value))
}
if value > max {
errors = append(errors, fmt.Errorf(
"%q cannot be higher than %d: %d", k, max, value))
}
return
}
} }
//data source validate func //data source validate func
@ -244,14 +533,19 @@ func validateNameRegex(v interface{}, k string) (ws []string, errors []error) {
} }
func validateImageOwners(v interface{}, k string) (ws []string, errors []error) { func validateImageOwners(v interface{}, k string) (ws []string, errors []error) {
return validation.StringInSlice([]string{ if value := v.(string); value != "" {
"", owners := ecs.ImageOwnerAlias(value)
string(ecs.ImageOwnerSystem), if owners != ecs.ImageOwnerSystem &&
string(ecs.ImageOwnerSelf), owners != ecs.ImageOwnerSelf &&
string(ecs.ImageOwnerOthers), owners != ecs.ImageOwnerOthers &&
string(ecs.ImageOwnerMarketplace), owners != ecs.ImageOwnerMarketplace &&
string(ecs.ImageOwnerDefault), owners != ecs.ImageOwnerDefault {
}, false)(v, k) errors = append(errors, fmt.Errorf(
"%q must contain a valid Image owner , expected %s, %s, %s, %s or %s, got %q",
k, ecs.ImageOwnerSystem, ecs.ImageOwnerSelf, ecs.ImageOwnerOthers, ecs.ImageOwnerMarketplace, ecs.ImageOwnerDefault, owners))
}
}
return
} }
func validateRegion(v interface{}, k string) (ws []string, errors []error) { func validateRegion(v interface{}, k string) (ws []string, errors []error) {

View File

@ -427,3 +427,76 @@ func TestValidateSlbListenerBandwidth(t *testing.T) {
} }
} }
} }
func TestValidateAllowedStringValue(t *testing.T) {
exceptValues := []string{"aliyun", "alicloud", "alibaba"}
validValues := []string{"aliyun"}
for _, v := range validValues {
_, errors := validateAllowedStringValue(exceptValues)(v, "allowvalue")
if len(errors) != 0 {
t.Fatalf("%q should be a valid value in %#v: %q", v, exceptValues, errors)
}
}
invalidValues := []string{"ali", "alidata", "terraform"}
for _, v := range invalidValues {
_, errors := validateAllowedStringValue(exceptValues)(v, "allowvalue")
if len(errors) == 0 {
t.Fatalf("%q should be an invalid value", v)
}
}
}
func TestValidateAllowedStringSplitValue(t *testing.T) {
exceptValues := []string{"aliyun", "alicloud", "alibaba"}
validValues := "aliyun,alicloud"
_, errors := validateAllowedSplitStringValue(exceptValues, ",")(validValues, "allowvalue")
if len(errors) != 0 {
t.Fatalf("%q should be a valid value in %#v: %q", validValues, exceptValues, errors)
}
invalidValues := "ali,alidata"
_, invalidErr := validateAllowedSplitStringValue(exceptValues, ",")(invalidValues, "allowvalue")
if len(invalidErr) == 0 {
t.Fatalf("%q should be an invalid value", invalidValues)
}
}
func TestValidateAllowedIntValue(t *testing.T) {
exceptValues := []int{1, 3, 5, 6}
validValues := []int{1, 3, 5, 6}
for _, v := range validValues {
_, errors := validateAllowedIntValue(exceptValues)(v, "allowvalue")
if len(errors) != 0 {
t.Fatalf("%q should be a valid value in %#v: %q", v, exceptValues, errors)
}
}
invalidValues := []int{0, 7, 10}
for _, v := range invalidValues {
_, errors := validateAllowedIntValue(exceptValues)(v, "allowvalue")
if len(errors) == 0 {
t.Fatalf("%q should be an invalid value", v)
}
}
}
func TestValidateIntegerInRange(t *testing.T) {
validIntegers := []int{-259, 0, 1, 5, 999}
min := -259
max := 999
for _, v := range validIntegers {
_, errors := validateIntegerInRange(min, max)(v, "name")
if len(errors) != 0 {
t.Fatalf("%q should be an integer in range (%d, %d): %q", v, min, max, errors)
}
}
invalidIntegers := []int{-260, -99999, 1000, 25678}
for _, v := range invalidIntegers {
_, errors := validateIntegerInRange(min, max)(v, "name")
if len(errors) == 0 {
t.Fatalf("%q should be an integer outside range (%d, %d)", v, min, max)
}
}
}

View File

@ -9,6 +9,39 @@ resource "alicloud_security_group" "group" {
description = "New security group" description = "New security group"
} }
resource "alicloud_security_group_rule" "http-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "internet"
policy = "accept"
port_range = "80/80"
priority = 1
security_group_id = "${alicloud_security_group.group.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_security_group_rule" "https-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "internet"
policy = "accept"
port_range = "443/443"
priority = 1
security_group_id = "${alicloud_security_group.group.id}"
cidr_ip = "0.0.0.0/0"
}
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.group.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_disk" "disk" { resource "alicloud_disk" "disk" {
availability_zone = "${var.availability_zones}" availability_zone = "${var.availability_zones}"

View File

@ -0,0 +1,33 @@
### Configure NAT instance Example
In the Virtual Private CloudVPC 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

View File

@ -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
}

View File

@ -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}"
}

View File

@ -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}

View File

@ -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"
}

View File

@ -3,33 +3,59 @@ resource "alicloud_security_group" "group" {
description = "New security group" description = "New security group"
} }
resource "alicloud_security_group_rule" "http-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "internet"
policy = "accept"
port_range = "80/80"
priority = 1
security_group_id = "${alicloud_security_group.group.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_security_group_rule" "https-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "internet"
policy = "accept"
port_range = "443/443"
priority = 1
security_group_id = "${alicloud_security_group.group.id}"
cidr_ip = "0.0.0.0/0"
}
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.group.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_instance" "instance" { resource "alicloud_instance" "instance" {
instance_name = "${var.short_name}-${var.role}-${format(var.count_format, count.index+1)}" instance_name = "${var.short_name}-${var.role}-${format(var.count_format, count.index+1)}"
host_name = "${var.short_name}-${var.role}-${format(var.count_format, count.index+1)}" host_name = "${var.short_name}-${var.role}-${format(var.count_format, count.index+1)}"
image_id = "${var.image_id}" image_id = "${var.image_id}"
instance_type = "${var.ecs_type}" instance_type = "${var.ecs_type}"
count = "${var.count}" count = "${var.count}"
availability_zone = "${var.availability_zones}"
security_groups = ["${alicloud_security_group.group.*.id}"] security_groups = ["${alicloud_security_group.group.*.id}"]
internet_charge_type = "${var.internet_charge_type}" internet_charge_type = "${var.internet_charge_type}"
internet_max_bandwidth_out = "${var.internet_max_bandwidth_out}" internet_max_bandwidth_out = "${var.internet_max_bandwidth_out}"
io_optimized = "${var.io_optimized}" io_optimized = "${var.io_optimized}"
password = "${var.ecs_password}" password = "${var.ecs_password}"
allocate_public_ip = "${var.allocate_public_ip}" allocate_public_ip = "${var.allocate_public_ip}"
availability_zone = ""
instance_charge_type = "PostPaid" instance_charge_type = "PostPaid"
system_disk_category = "cloud_efficiency" system_disk_category = "cloud_efficiency"
tags { tags {
role = "${var.role}" role = "${var.role}"
dc = "${var.datacenter}" dc = "${var.datacenter}"
} }
} }
resource "alicloud_slb" "instance" { resource "alicloud_slb" "instance" {

View File

@ -11,27 +11,38 @@ resource "alicloud_vswitch" "vsw" {
} }
resource "alicloud_security_group" "sg" { resource "alicloud_security_group" "sg" {
name = "tf-sg" name = "tf-sg"
description = "sg" description = "sg"
vpc_id = "${alicloud_vpc.default.id}" 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" { resource "alicloud_instance" "website" {
# cn-beijing # cn-beijing
availability_zone = "${var.zone}" availability_zone = "${var.zone}"
vswitch_id = "${alicloud_vswitch.vsw.id}" vswitch_id = "${alicloud_vswitch.vsw.id}"
image_id = "${var.image}" image_id = "${var.image}"
# series II # series II
instance_type = "${var.ecs_type}" instance_type = "${var.ecs_type}"
io_optimized = "optimized" io_optimized = "optimized"
system_disk_category = "cloud_efficiency" system_disk_category = "cloud_efficiency"
internet_charge_type = "PayByTraffic" internet_charge_type = "PayByTraffic"
internet_max_bandwidth_out = 5 internet_max_bandwidth_out = 5
allocate_public_ip = true allocate_public_ip = true
security_groups = ["${alicloud_security_group.sg.id}"] security_groups = ["${alicloud_security_group.sg.id}"]
instance_name = "test_foo" instance_name = "tf_website"
password= "${var.password}"
user_data = "${file("userdata.sh")}" user_data = "${file("userdata.sh")}"
} }

View File

@ -1,7 +1,8 @@
output "hostname" {
value = "${alicloud_instance.website.instance_name}"
}
output "ecs_id" { output "ecs_id" {
value = "${alicloud_instance.website.id}" value = "${alicloud_instance.website.id}"
} }
output "ecs_public_ip" {
value = "${alicloud_instance.website.public_ip}"
}

View File

@ -10,6 +10,10 @@ variable "zone" {
default = "cn-beijing-b" default = "cn-beijing-b"
} }
variable "password" {
default = "Test123456"
}
variable "image" { variable "image" {
default = "ubuntu_140405_32_40G_cloudinit_20161115.vhd" default = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
} }

View File

@ -1,6 +1,3 @@
provider "alicloud" {
region = "${var.region}"
}
module "vpc" { module "vpc" {
availability_zones = "${var.availability_zones}" availability_zones = "${var.availability_zones}"
@ -21,14 +18,12 @@ module "control-nodes" {
role = "control" role = "control"
datacenter = "${var.datacenter}" datacenter = "${var.datacenter}"
ecs_type = "${var.control_ecs_type}" ecs_type = "${var.control_ecs_type}"
ecs_password = "${var.ecs_password}"
disk_size = "${var.control_disk_size}" disk_size = "${var.control_disk_size}"
ssh_username = "${var.ssh_username}" ssh_username = "${var.ssh_username}"
short_name = "${var.short_name}" short_name = "${var.short_name}"
availability_zones = "${module.vpc.availability_zones}" availability_zones = "${module.vpc.availability_zones}"
security_groups = ["${module.security-groups.control_security_group}"] security_groups = ["${module.security-groups.control_security_group}"]
vswitch_id = "${module.vpc.vswitch_ids}" vswitch_id = "${module.vpc.vswitch_ids}"
internet_charge_type = "${var.internet_charge_type}"
} }
module "edge-nodes" { module "edge-nodes" {
@ -37,13 +32,11 @@ module "edge-nodes" {
role = "edge" role = "edge"
datacenter = "${var.datacenter}" datacenter = "${var.datacenter}"
ecs_type = "${var.edge_ecs_type}" ecs_type = "${var.edge_ecs_type}"
ecs_password = "${var.ecs_password}"
ssh_username = "${var.ssh_username}" ssh_username = "${var.ssh_username}"
short_name = "${var.short_name}" short_name = "${var.short_name}"
availability_zones = "${module.vpc.availability_zones}" availability_zones = "${module.vpc.availability_zones}"
security_groups = ["${module.security-groups.worker_security_group}"] security_groups = ["${module.security-groups.worker_security_group}"]
vswitch_id = "${module.vpc.vswitch_ids}" vswitch_id = "${module.vpc.vswitch_ids}"
internet_charge_type = "${var.internet_charge_type}"
} }
module "worker-nodes" { module "worker-nodes" {
@ -52,11 +45,9 @@ module "worker-nodes" {
role = "worker" role = "worker"
datacenter = "${var.datacenter}" datacenter = "${var.datacenter}"
ecs_type = "${var.worker_ecs_type}" ecs_type = "${var.worker_ecs_type}"
ecs_password = "${var.ecs_password}"
ssh_username = "${var.ssh_username}" ssh_username = "${var.ssh_username}"
short_name = "${var.short_name}" short_name = "${var.short_name}"
availability_zones = "${module.vpc.availability_zones}" availability_zones = "${module.vpc.availability_zones}"
security_groups = ["${module.security-groups.worker_security_group}"] security_groups = ["${module.security-groups.worker_security_group}"]
vswitch_id = "${module.vpc.vswitch_ids}" vswitch_id = "${module.vpc.vswitch_ids}"
internet_charge_type = "${var.internet_charge_type}"
} }

View File

@ -50,10 +50,6 @@ variable "availability_zones" {
default = "cn-beijing-c" default = "cn-beijing-c"
} }
variable "internet_charge_type" {
default = ""
}
variable "datacenter" { variable "datacenter" {
default = "beijing" default = "beijing"
} }

View File

@ -18,6 +18,7 @@ variable "short_name" {
variable "ecs_type" { variable "ecs_type" {
} }
variable "ecs_password" { variable "ecs_password" {
default = "Test12345"
} }
variable "availability_zones" { variable "availability_zones" {
} }

View File

@ -5,7 +5,7 @@ data "alicloud_instance_types" "1c2g" {
} }
data "alicloud_zones" "default" { 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}" "available_disk_category"= "${var.disk_category}"
} }
@ -14,6 +14,39 @@ resource "alicloud_security_group" "group" {
description = "New security group" description = "New security group"
} }
resource "alicloud_security_group_rule" "http-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "internet"
policy = "accept"
port_range = "80/80"
priority = 1
security_group_id = "${alicloud_security_group.group.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_security_group_rule" "https-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "internet"
policy = "accept"
port_range = "443/443"
priority = 1
security_group_id = "${alicloud_security_group.group.id}"
cidr_ip = "0.0.0.0/0"
}
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.group.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_instance" "instance" { resource "alicloud_instance" "instance" {
instance_name = "${var.short_name}-${var.role}-${format(var.count_format, count.index+1)}" instance_name = "${var.short_name}-${var.role}-${format(var.count_format, count.index+1)}"
host_name = "${var.short_name}-${var.role}-${format(var.count_format, count.index+1)}" host_name = "${var.short_name}-${var.role}-${format(var.count_format, count.index+1)}"

View File

@ -1,11 +1,39 @@
data "alicloud_instance_types" "instance_type" {
instance_type_family = "ecs.n1"
cpu_core_count = "1"
memory_size = "2"
}
resource "alicloud_security_group" "group" { resource "alicloud_security_group" "group" {
name = "${var.short_name}" name = "${var.short_name}"
description = "New security group" description = "New security group"
} }
resource "alicloud_security_group_rule" "allow_http_80" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "${var.nic_type}"
policy = "accept"
port_range = "80/80"
priority = 1
security_group_id = "${alicloud_security_group.group.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_security_group_rule" "allow_https_443" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "${var.nic_type}"
policy = "accept"
port_range = "443/443"
priority = 1
security_group_id = "${alicloud_security_group.group.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_disk" "disk" { resource "alicloud_disk" "disk" {
availability_zone = "${var.availability_zones}" availability_zone = "${alicloud_instance.instance.0.availability_zone}"
category = "${var.disk_category}" category = "${var.disk_category}"
size = "${var.disk_size}" size = "${var.disk_size}"
count = "${var.count}" count = "${var.count}"
@ -15,7 +43,7 @@ resource "alicloud_instance" "instance" {
instance_name = "${var.short_name}-${var.role}-${format(var.count_format, count.index+1)}" instance_name = "${var.short_name}-${var.role}-${format(var.count_format, count.index+1)}"
host_name = "${var.short_name}-${var.role}-${format(var.count_format, count.index+1)}" host_name = "${var.short_name}-${var.role}-${format(var.count_format, count.index+1)}"
image_id = "${var.image_id}" image_id = "${var.image_id}"
instance_type = "${var.ecs_type}" instance_type = "${data.alicloud_instance_types.instance_type.instance_types.0.id}"
count = "${var.count}" count = "${var.count}"
availability_zone = "${var.availability_zones}" availability_zone = "${var.availability_zones}"
security_groups = ["${alicloud_security_group.group.*.id}"] security_groups = ["${alicloud_security_group.group.*.id}"]
@ -46,4 +74,3 @@ resource "alicloud_disk_attachment" "instance-attachment" {
instance_id = "${element(alicloud_instance.instance.*.id, count.index)}" instance_id = "${element(alicloud_instance.instance.*.id, count.index)}"
device_name = "${var.device_name}" device_name = "${var.device_name}"
} }

View File

@ -8,6 +8,10 @@ variable "image_id" {
default = "ubuntu_140405_64_40G_cloudinit_20161115.vhd" default = "ubuntu_140405_64_40G_cloudinit_20161115.vhd"
} }
variable "availability_zones" {
default = ""
}
variable "role" { variable "role" {
default = "work" default = "work"
} }
@ -23,9 +27,6 @@ variable "ecs_type" {
variable "ecs_password" { variable "ecs_password" {
default = "Test12345" default = "Test12345"
} }
variable "availability_zones" {
default = "cn-beijing-b"
}
variable "allocate_public_ip" { variable "allocate_public_ip" {
default = true default = true
} }
@ -41,7 +42,7 @@ variable "io_optimized" {
} }
variable "disk_category" { variable "disk_category" {
default = "cloud_ssd" default = "cloud_efficiency"
} }
variable "disk_size" { variable "disk_size" {
default = "40" default = "40"
@ -49,3 +50,7 @@ variable "disk_size" {
variable "device_name" { variable "device_name" {
default = "/dev/xvdb" default = "/dev/xvdb"
} }
variable "nic_type" {
default = "internet"
}

View File

@ -0,0 +1,17 @@
### RDS Example
The example launches RDS instance, database, account and grant the database readwrite privilege to the account.
### Get up and running
* Planning phase
terraform plan
* Apply phase
terraform apply
* Destroy
terraform destroy

View File

@ -0,0 +1,17 @@
resource "alicloud_db_instance" "dc" {
engine = "${var.engine}"
engine_version = "${var.engine_version}"
db_instance_class = "${var.instance_class}"
db_instance_storage = "${var.storage}"
db_instance_net_type = "${var.net_type}"
master_user_name = "${var.user_name}"
master_user_password = "${var.password}"
db_mappings = [{
db_name = "${var.database_name}"
character_set_name = "${var.database_character}"
db_description = "tf"
}]
}

View File

@ -0,0 +1,11 @@
output "port" {
value = "${alicloud_db_instance.dc.port}"
}
output "connections" {
value = "${alicloud_db_instance.dc.connections}"
}
output "security_ips" {
value = "${alicloud_db_instance.dc.security_ips}"
}

View File

@ -0,0 +1,29 @@
variable "engine" {
default = "MySQL"
}
variable "engine_version" {
default = "5.6"
}
variable "instance_class" {
default = "rds.mysql.t1.small"
}
variable "storage" {
default = "10"
}
variable "net_type" {
default = "Intranet"
}
variable "user_name" {
default = "tf_tester"
}
variable "password" {
default = "Test12345"
}
variable "database_name" {
default = "bookstore"
}
variable "database_character" {
default = "utf8"
}

View File

@ -2,12 +2,23 @@ resource "alicloud_security_group" "default" {
name = "${var.security_group_name}" name = "${var.security_group_name}"
} }
resource "alicloud_security_group_rule" "allow_all_tcp" { resource "alicloud_security_group_rule" "http-in" {
type = "ingress" type = "ingress"
ip_protocol = "tcp" ip_protocol = "tcp"
nic_type = "${var.nic_type}" nic_type = "internet"
policy = "accept" policy = "accept"
port_range = "1/65535" port_range = "80/80"
priority = 1
security_group_id = "${alicloud_security_group.default.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_security_group_rule" "ssh-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "internet"
policy = "accept"
port_range = "22/22"
priority = 1 priority = 1
security_group_id = "${alicloud_security_group.default.id}" security_group_id = "${alicloud_security_group.default.id}"
cidr_ip = "0.0.0.0/0" cidr_ip = "0.0.0.0/0"

Binary file not shown.

View File

@ -5,21 +5,50 @@ resource "alicloud_slb" "instance" {
listener = [ listener = [
{ {
"instance_port" = "2111" "instance_port" = "22"
"lb_port" = "21" "lb_port" = "22"
"lb_protocol" = "tcp" "lb_protocol" = "tcp"
"bandwidth" = "5" "bandwidth" = "10"
"health_check_type" = "http"
"persistence_timeout" = 3600
"healthy_threshold" = 8
"unhealthy_threshold" = 8
"health_check_timeout" = 8
"health_check_interval" = 5
"health_check_http_code" = "http_2xx,http_3xx"
"health_check_timeout" = 8
}, },
{ {
"instance_port" = "8000" "instance_port" = "2001"
"lb_port" = "80" "lb_port" = "2001"
"lb_protocol" = "http"
"bandwidth" = "5"
},
{
"instance_port" = "1611"
"lb_port" = "161"
"lb_protocol" = "udp" "lb_protocol" = "udp"
"bandwidth" = "5" "bandwidth" = "10"
}] "persistence_timeout" = 3600
"healthy_threshold" = 8
"unhealthy_threshold" = 8
"health_check_timeout" = 8
"health_check_interval" = 4
"health_check_timeout" = 8
},
{
"instance_port" = "80"
"lb_port" = "80"
"lb_protocol" = "http"
"sticky_session" = "on"
"sticky_session_type" = "server"
"cookie" = "testslblistenercookie"
"cookie_timeout" = 86400
"health_check" = "on"
"health_check_domain" = "$_ip"
"health_check_uri" = "/console"
"health_check_connect_port" = 20
"healthy_threshold" = 8
"unhealthy_threshold" = 8
"health_check_timeout" = 8
"health_check_interval" = 5
"health_check_http_code" = "http_2xx,http_3xx"
"bandwidth" = 10
}]
} }

View File

@ -23,9 +23,9 @@ resource "alicloud_security_group" "sg" {
vpc_id = "${alicloud_vpc.default.id}" vpc_id = "${alicloud_vpc.default.id}"
} }
resource "alicloud_security_group_rule" "ssh" { resource "alicloud_security_group_rule" "ssh-in" {
type = "ingress" type = "ingress"
ip_protocol = "tcp" ip_protocol = "tcp"
nic_type = "intranet" nic_type = "intranet"
policy = "${var.rule_policy}" policy = "${var.rule_policy}"
port_range = "22/22" port_range = "22/22"
@ -34,6 +34,28 @@ resource "alicloud_security_group_rule" "ssh" {
cidr_ip = "0.0.0.0/0" cidr_ip = "0.0.0.0/0"
} }
resource "alicloud_security_group_rule" "http-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "internet"
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_security_group_rule" "https-in" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "internet"
policy = "accept"
port_range = "443/443"
priority = 1
security_group_id = "${alicloud_security_group.sg.id}"
cidr_ip = "0.0.0.0/0"
}
resource "alicloud_instance" "snat" { resource "alicloud_instance" "snat" {
# cn-beijing # cn-beijing
availability_zone = "${var.zone_id}" availability_zone = "${var.zone_id}"

View File

@ -7,8 +7,8 @@ import (
"log" "log"
"net/http" "net/http"
"net/url" "net/url"
"time"
"strings" "strings"
"time"
"github.com/denverdino/aliyungo/util" "github.com/denverdino/aliyungo/util"
) )
@ -21,6 +21,9 @@ type Client struct {
httpClient *http.Client httpClient *http.Client
endpoint string endpoint string
version string version string
serviceCode string
regionID Region
businessInfo string
} }
// NewClient creates a new instance of ECS client // NewClient creates a new instance of ECS client
@ -33,6 +36,26 @@ func (client *Client) Init(endpoint, version, accessKeyId, accessKeySecret strin
client.version = version client.version = version
} }
func (client *Client) NewInit(endpoint, version, accessKeyId, accessKeySecret, serviceCode string, regionID Region) {
client.Init(endpoint, version, accessKeyId, accessKeySecret)
client.serviceCode = serviceCode
client.regionID = regionID
client.setEndpointByLocation(regionID, serviceCode, accessKeyId, accessKeySecret)
}
//NewClient using location service
func (client *Client) setEndpointByLocation(region Region, serviceCode, accessKeyId, accessKeySecret string) {
locationClient := NewLocationClient(accessKeyId, accessKeySecret)
ep := locationClient.DescribeOpenAPIEndpoint(region, serviceCode)
if ep == "" {
ep = loadEndpointFromFile(region, serviceCode)
}
if ep != "" {
client.endpoint = ep
}
}
// SetEndpoint sets custom endpoint // SetEndpoint sets custom endpoint
func (client *Client) SetEndpoint(endpoint string) { func (client *Client) SetEndpoint(endpoint string) {
client.endpoint = endpoint client.endpoint = endpoint
@ -43,6 +66,15 @@ func (client *Client) SetVersion(version string) {
client.version = version client.version = version
} }
func (client *Client) SetRegionID(regionID Region) {
client.regionID = regionID
}
//SetServiceCode sets serviceCode
func (client *Client) SetServiceCode(serviceCode string) {
client.serviceCode = serviceCode
}
// SetAccessKeyId sets new AccessKeyId // SetAccessKeyId sets new AccessKeyId
func (client *Client) SetAccessKeyId(id string) { func (client *Client) SetAccessKeyId(id string) {
client.AccessKeyId = id client.AccessKeyId = id
@ -58,6 +90,15 @@ func (client *Client) SetDebug(debug bool) {
client.debug = debug client.debug = debug
} }
// SetBusinessInfo sets business info to log the request/response message
func (client *Client) SetBusinessInfo(businessInfo string) {
if strings.HasPrefix(businessInfo, "/") {
client.businessInfo = businessInfo
} else if businessInfo != "" {
client.businessInfo = "/" + businessInfo
}
}
// Invoke sends the raw HTTP request for ECS services // Invoke sends the raw HTTP request for ECS services
func (client *Client) Invoke(action string, args interface{}, response interface{}) error { func (client *Client) Invoke(action string, args interface{}, response interface{}) error {
@ -80,7 +121,7 @@ func (client *Client) Invoke(action string, args interface{}, response interface
} }
// TODO move to util and add build val flag // TODO move to util and add build val flag
httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version) httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
t0 := time.Now() t0 := time.Now()
httpResp, err := client.httpClient.Do(httpReq) httpResp, err := client.httpClient.Do(httpReq)
@ -128,7 +169,8 @@ func (client *Client) Invoke(action string, args interface{}, response interface
// Invoke sends the raw HTTP request for ECS services // Invoke sends the raw HTTP request for ECS services
//改进了一下上面那个方法可以使用各种Http方法 //改进了一下上面那个方法可以使用各种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 := Request{}
request.init(client.version, action, client.AccessKeyId) request.init(client.version, action, client.AccessKeyId)
@ -140,17 +182,18 @@ func (client *Client) InvokeByAnyMethod(method, action string, args interface{},
signature := util.CreateSignatureForRequest(method, &data, client.AccessKeySecret) signature := util.CreateSignatureForRequest(method, &data, client.AccessKeySecret)
data.Add("Signature", signature) data.Add("Signature", signature)
// Generate the request URL // Generate the request URL
var ( var (
httpReq *http.Request httpReq *http.Request
err error err error
) )
if method == http.MethodGet { 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) httpReq, err = http.NewRequest(method, requestURL, nil)
} else { } 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") httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
} }
@ -159,7 +202,7 @@ func (client *Client) InvokeByAnyMethod(method, action string, args interface{},
} }
// TODO move to util and add build val flag // TODO move to util and add build val flag
httpReq.Header.Set("X-SDK-Client", `AliyunGO/` + Version) httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
t0 := time.Now() t0 := time.Now()
httpResp, err := client.httpClient.Do(httpReq) httpResp, err := client.httpClient.Do(httpReq)

View File

@ -0,0 +1,118 @@
package common
import (
"encoding/xml"
"fmt"
"io/ioutil"
"os"
"strings"
)
const (
// LocationDefaultEndpoint is the default API endpoint of Location services
locationDefaultEndpoint = "https://location.aliyuncs.com"
locationAPIVersion = "2015-06-12"
HTTP_PROTOCOL = "http"
HTTPS_PROTOCOL = "https"
)
var (
endpoints = make(map[Region]map[string]string)
)
//init endpoints from file
func init() {
}
func NewLocationClient(accessKeyId, accessKeySecret string) *Client {
endpoint := os.Getenv("LOCATION_ENDPOINT")
if endpoint == "" {
endpoint = locationDefaultEndpoint
}
client := &Client{}
client.Init(endpoint, locationAPIVersion, accessKeyId, accessKeySecret)
return client
}
func (client *Client) DescribeEndpoint(args *DescribeEndpointArgs) (*DescribeEndpointResponse, error) {
response := &DescribeEndpointResponse{}
err := client.Invoke("DescribeEndpoint", args, response)
if err != nil {
return nil, err
}
return response, err
}
func getProductRegionEndpoint(region Region, serviceCode string) string {
if sp, ok := endpoints[region]; ok {
if endpoint, ok := sp[serviceCode]; ok {
return endpoint
}
}
return ""
}
func setProductRegionEndpoint(region Region, serviceCode string, endpoint string) {
endpoints[region] = map[string]string{
serviceCode: endpoint,
}
}
func (client *Client) DescribeOpenAPIEndpoint(region Region, serviceCode string) string {
if endpoint := getProductRegionEndpoint(region, serviceCode); endpoint != "" {
return endpoint
}
defaultProtocols := HTTP_PROTOCOL
args := &DescribeEndpointArgs{
Id: region,
ServiceCode: serviceCode,
Type: "openAPI",
}
endpoint, err := client.DescribeEndpoint(args)
if err != nil || endpoint.Endpoint == "" {
return ""
}
for _, protocol := range endpoint.Protocols.Protocols {
if strings.ToLower(protocol) == HTTPS_PROTOCOL {
defaultProtocols = HTTPS_PROTOCOL
break
}
}
ep := fmt.Sprintf("%s://%s", defaultProtocols, endpoint.Endpoint)
setProductRegionEndpoint(region, serviceCode, ep)
return ep
}
func loadEndpointFromFile(region Region, serviceCode string) string {
data, err := ioutil.ReadFile("./endpoints.xml")
if err != nil {
return ""
}
var endpoints Endpoints
err = xml.Unmarshal(data, &endpoints)
if err != nil {
return ""
}
for _, endpoint := range endpoints.Endpoint {
if endpoint.RegionIds.RegionId == string(region) {
for _, product := range endpoint.Products.Product {
if strings.ToLower(product.ProductName) == serviceCode {
return fmt.Sprintf("%s://%s", HTTPS_PROTOCOL, product.DomainName)
}
}
}
}
return ""
}

File diff suppressed because it is too large Load Diff

View File

@ -5,23 +5,28 @@ type Region string
// Constants of region definition // Constants of region definition
const ( const (
Hangzhou = Region("cn-hangzhou") Hangzhou = Region("cn-hangzhou")
Qingdao = Region("cn-qingdao") Qingdao = Region("cn-qingdao")
Beijing = Region("cn-beijing") Beijing = Region("cn-beijing")
Hongkong = Region("cn-hongkong") Hongkong = Region("cn-hongkong")
Shenzhen = Region("cn-shenzhen") Shenzhen = Region("cn-shenzhen")
USWest1 = Region("us-west-1") Shanghai = Region("cn-shanghai")
USEast1 = Region("us-east-1") Zhangjiakou = Region("cn-zhangjiakou")
APSouthEast1 = Region("ap-southeast-1") APSouthEast1 = Region("ap-southeast-1")
Shanghai = Region("cn-shanghai")
MEEast1 = Region("me-east-1")
APNorthEast1 = Region("ap-northeast-1") APNorthEast1 = Region("ap-northeast-1")
APSouthEast2 = Region("ap-southeast-2") APSouthEast2 = Region("ap-southeast-2")
EUCentral1 = Region("eu-central-1")
USWest1 = Region("us-west-1")
USEast1 = Region("us-east-1")
MEEast1 = Region("me-east-1")
EUCentral1 = Region("eu-central-1")
) )
var ValidRegions = []Region{ var ValidRegions = []Region{
Hangzhou, Qingdao, Beijing, Shenzhen, Hongkong, Shanghai, Hangzhou, Qingdao, Beijing, Shenzhen, Hongkong, Shanghai, Zhangjiakou,
USWest1, USEast1, USWest1, USEast1,
APNorthEast1, APSouthEast1, APSouthEast2, APNorthEast1, APSouthEast1, APSouthEast2,
MEEast1, MEEast1,

View File

@ -13,3 +13,77 @@ const (
PrePaid = InstanceChargeType("PrePaid") PrePaid = InstanceChargeType("PrePaid")
PostPaid = InstanceChargeType("PostPaid") PostPaid = InstanceChargeType("PostPaid")
) )
type DescribeEndpointArgs struct {
Id Region
ServiceCode string
Type string
}
type EndpointItem struct {
Protocols struct {
Protocols []string
}
Type string
Namespace string
Id Region
SerivceCode string
Endpoint string
}
type DescribeEndpointResponse struct {
Response
EndpointItem
}
type NetType string
const (
Internet = NetType("Internet")
Intranet = NetType("Intranet")
)
type TimeType string
const (
Hour = TimeType("Hour")
Day = TimeType("Day")
Month = TimeType("Month")
Year = TimeType("Year")
)
type NetworkType string
const (
Classic = NetworkType("Classic")
VPC = NetworkType("VPC")
)
type BusinessInfo struct {
Pack string `json:"pack,omitempty"`
ActivityId string `json:"activityId,omitempty"`
}
//xml
type Endpoints struct {
Endpoint []Endpoint `xml:"Endpoint"`
}
type Endpoint struct {
Name string `xml:"name,attr"`
RegionIds RegionIds `xml:"RegionIds"`
Products Products `xml:"Products"`
}
type RegionIds struct {
RegionId string `xml:"RegionId"`
}
type Products struct {
Product []Product `xml:"Product"`
}
type Product struct {
ProductName string `xml:"ProductName"`
DomainName string `xml:"DomainName"`
}

View File

@ -1,8 +1,9 @@
package ecs package ecs
import ( import (
"github.com/denverdino/aliyungo/common"
"os" "os"
"github.com/denverdino/aliyungo/common"
) )
// Interval for checking status in WaitForXXX method // Interval for checking status in WaitForXXX method
@ -19,6 +20,12 @@ const (
// ECSDefaultEndpoint is the default API endpoint of ECS services // ECSDefaultEndpoint is the default API endpoint of ECS services
ECSDefaultEndpoint = "https://ecs-cn-hangzhou.aliyuncs.com" ECSDefaultEndpoint = "https://ecs-cn-hangzhou.aliyuncs.com"
ECSAPIVersion = "2014-05-26" ECSAPIVersion = "2014-05-26"
ECSServiceCode = "ecs"
VPCDefaultEndpoint = "https://vpc.aliyuncs.com"
VPCAPIVersion = "2016-04-28"
VPCServiceCode = "vpc"
) )
// NewClient creates a new instance of ECS client // NewClient creates a new instance of ECS client
@ -30,8 +37,38 @@ func NewClient(accessKeyId, accessKeySecret string) *Client {
return NewClientWithEndpoint(endpoint, accessKeyId, accessKeySecret) return NewClientWithEndpoint(endpoint, accessKeyId, accessKeySecret)
} }
func NewECSClient(accessKeyId, accessKeySecret string, regionID common.Region) *Client {
endpoint := os.Getenv("ECS_ENDPOINT")
if endpoint == "" {
endpoint = ECSDefaultEndpoint
}
return NewClientWithRegion(endpoint, accessKeyId, accessKeySecret, regionID)
}
func NewClientWithRegion(endpoint string, accessKeyId, accessKeySecret string, regionID common.Region) *Client {
client := &Client{}
client.NewInit(endpoint, ECSAPIVersion, accessKeyId, accessKeySecret, ECSServiceCode, regionID)
return client
}
func NewClientWithEndpoint(endpoint string, accessKeyId, accessKeySecret string) *Client { func NewClientWithEndpoint(endpoint string, accessKeyId, accessKeySecret string) *Client {
client := &Client{} client := &Client{}
client.Init(endpoint, ECSAPIVersion, accessKeyId, accessKeySecret) client.Init(endpoint, ECSAPIVersion, accessKeyId, accessKeySecret)
return client return client
} }
func NewVPCClient(accessKeyId, accessKeySecret string, regionID common.Region) *Client {
endpoint := os.Getenv("VPC_ENDPOINT")
if endpoint == "" {
endpoint = VPCDefaultEndpoint
}
return NewVPCClientWithRegion(endpoint, accessKeyId, accessKeySecret, regionID)
}
func NewVPCClientWithRegion(endpoint string, accessKeyId, accessKeySecret string, regionID common.Region) *Client {
client := &Client{}
client.NewInit(endpoint, VPCAPIVersion, accessKeyId, accessKeySecret, VPCServiceCode, regionID)
return client
}

View File

@ -63,8 +63,12 @@ type DescribeImagesResponse struct {
type DiskDeviceMapping struct { type DiskDeviceMapping struct {
SnapshotId string SnapshotId string
//Why Size Field is string-type. //Why Size Field is string-type.
Size string Size string
Device string Device string
//For import images
Format string
OSSBucket string
OSSObject string
} }
// //
@ -112,6 +116,7 @@ func (client *Client) DescribeImages(args *DescribeImagesArgs) (images []ImageTy
type CreateImageArgs struct { type CreateImageArgs struct {
RegionId common.Region RegionId common.Region
SnapshotId string SnapshotId string
InstanceId string
ImageName string ImageName string
ImageVersion string ImageVersion string
Description string Description string
@ -227,6 +232,38 @@ func (client *Client) CopyImage(args *CopyImageArgs) (string, error) {
return response.ImageId, nil return response.ImageId, nil
} }
// ImportImageArgs repsents arguements to import image from oss
type ImportImageArgs struct {
RegionId common.Region
ImageName string
ImageVersion string
Description string
ClientToken string
Architecture string
OSType string
Platform string
DiskDeviceMappings struct {
DiskDeviceMapping []DiskDeviceMapping
}
}
func (client *Client) ImportImage(args *ImportImageArgs) (string, error) {
response := &CopyImageResponse{}
err := client.Invoke("ImportImage", args, &response)
if err != nil {
return "", err
}
return response.ImageId, nil
}
type ImportImageResponse struct {
common.Response
RegionId common.Region
ImageId string
ImportTaskId string
}
// Default timeout value for WaitForImageReady method // Default timeout value for WaitForImageReady method
const ImageDefaultTimeout = 120 const ImageDefaultTimeout = 120

View File

@ -15,12 +15,14 @@ type InstanceStatus string
// Constants of InstanceStatus // Constants of InstanceStatus
const ( const (
Creating = InstanceStatus("Creating") Creating = InstanceStatus("Creating") // For backward compatability
Pending = InstanceStatus("Pending")
Running = InstanceStatus("Running") Running = InstanceStatus("Running")
Starting = InstanceStatus("Starting") Starting = InstanceStatus("Starting")
Stopped = InstanceStatus("Stopped") Stopped = InstanceStatus("Stopped")
Stopping = InstanceStatus("Stopping") Stopping = InstanceStatus("Stopping")
Deleted = InstanceStatus("Deleted")
) )
type LockReason string type LockReason string
@ -279,6 +281,7 @@ type ModifyInstanceAttributeArgs struct {
Description string Description string
Password string Password string
HostName string HostName string
UserData string
} }
type ModifyInstanceAttributeResponse struct { type ModifyInstanceAttributeResponse struct {
@ -323,6 +326,38 @@ func (client *Client) WaitForInstance(instanceId string, status InstanceStatus,
return nil 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
}
time.Sleep(DefaultWaitForInterval * time.Second)
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 { type DescribeInstanceVncUrlArgs struct {
RegionId common.Region RegionId common.Region
InstanceId string InstanceId string
@ -510,6 +545,43 @@ func (client *Client) CreateInstance(args *CreateInstanceArgs) (instanceId strin
return response.InstanceId, err 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"`
ActivityId string `json:"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 { type SecurityGroupArgs struct {
InstanceId string InstanceId string
SecurityGroupId string SecurityGroupId string

View File

@ -1,8 +1,7 @@
package alicloud package ecs
import ( import (
"github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
) )
type BandwidthPackageType struct { type BandwidthPackageType struct {
@ -25,6 +24,10 @@ type ForwardTableIdType struct {
ForwardTableId []string ForwardTableId []string
} }
type SnatTableIdType struct {
SnatTableId []string
}
type BandwidthPackageIdType struct { type BandwidthPackageIdType struct {
BandwidthPackageId []string BandwidthPackageId []string
} }
@ -39,7 +42,7 @@ type CreateNatGatewayResponse struct {
// CreateNatGateway creates Virtual Private Cloud // CreateNatGateway creates Virtual Private Cloud
// //
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/vpc&createvpc // You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/vpc&createvpc
func CreateNatGateway(client *ecs.Client, args *CreateNatGatewayArgs) (resp *CreateNatGatewayResponse, err error) { func (client *Client) CreateNatGateway(args *CreateNatGatewayArgs) (resp *CreateNatGatewayResponse, err error) {
response := CreateNatGatewayResponse{} response := CreateNatGatewayResponse{}
err = client.Invoke("CreateNatGateway", args, &response) err = client.Invoke("CreateNatGateway", args, &response)
if err != nil { if err != nil {
@ -53,6 +56,7 @@ type NatGatewaySetType struct {
Description string Description string
BandwidthPackageIds BandwidthPackageIdType BandwidthPackageIds BandwidthPackageIdType
ForwardTableIds ForwardTableIdType ForwardTableIds ForwardTableIdType
SnatTableIds SnatTableIdType
InstanceChargeType string InstanceChargeType string
Name string Name string
NatGatewayId string NatGatewayId string
@ -77,7 +81,7 @@ type DescribeNatGatewaysArgs struct {
common.Pagination common.Pagination
} }
func DescribeNatGateways(client *ecs.Client, args *DescribeNatGatewaysArgs) (natGateways []NatGatewaySetType, func (client *Client) DescribeNatGateways(args *DescribeNatGatewaysArgs) (natGateways []NatGatewaySetType,
pagination *common.PaginationResult, err error) { pagination *common.PaginationResult, err error) {
args.Validate() args.Validate()
@ -103,7 +107,7 @@ type ModifyNatGatewayAttributeResponse struct {
common.Response common.Response
} }
func ModifyNatGatewayAttribute(client *ecs.Client, args *ModifyNatGatewayAttributeArgs) error { func (client *Client) ModifyNatGatewayAttribute(args *ModifyNatGatewayAttributeArgs) error {
response := ModifyNatGatewayAttributeResponse{} response := ModifyNatGatewayAttributeResponse{}
return client.Invoke("ModifyNatGatewayAttribute", args, &response) return client.Invoke("ModifyNatGatewayAttribute", args, &response)
} }
@ -114,7 +118,7 @@ type ModifyNatGatewaySpecArgs struct {
Spec NatGatewaySpec Spec NatGatewaySpec
} }
func ModifyNatGatewaySpec(client *ecs.Client, args *ModifyNatGatewaySpecArgs) error { func (client *Client) ModifyNatGatewaySpec(args *ModifyNatGatewaySpecArgs) error {
response := ModifyNatGatewayAttributeResponse{} response := ModifyNatGatewayAttributeResponse{}
return client.Invoke("ModifyNatGatewaySpec", args, &response) return client.Invoke("ModifyNatGatewaySpec", args, &response)
} }
@ -128,7 +132,7 @@ type DeleteNatGatewayResponse struct {
common.Response common.Response
} }
func DeleteNatGateway(client *ecs.Client, args *DeleteNatGatewayArgs) error { func (client *Client) DeleteNatGateway(args *DeleteNatGatewayArgs) error {
response := DeleteNatGatewayResponse{} response := DeleteNatGatewayResponse{}
err := client.Invoke("DeleteNatGateway", args, &response) err := client.Invoke("DeleteNatGateway", args, &response)
return err return err
@ -140,10 +144,20 @@ type DescribeBandwidthPackagesArgs struct {
NatGatewayId string NatGatewayId string
} }
type PublicIpAddresseType struct {
AllocationId string
IpAddress string
}
type DescribeBandwidthPackageType struct { type DescribeBandwidthPackageType struct {
Bandwidth string Bandwidth string
BandwidthPackageId string BandwidthPackageId string
IpCount string IpCount string
PublicIpAddresses struct {
PublicIpAddresse []PublicIpAddresseType
}
ZoneId string
} }
type DescribeBandwidthPackagesResponse struct { type DescribeBandwidthPackagesResponse struct {
@ -153,12 +167,14 @@ type DescribeBandwidthPackagesResponse struct {
} }
} }
func DescribeBandwidthPackages(client *ecs.Client, args *DescribeBandwidthPackagesArgs) ([]DescribeBandwidthPackageType, error) { func (client *Client) DescribeBandwidthPackages(args *DescribeBandwidthPackagesArgs) ([]DescribeBandwidthPackageType, error) {
response := &DescribeBandwidthPackagesResponse{} response := &DescribeBandwidthPackagesResponse{}
err := client.Invoke("DescribeBandwidthPackages", args, response) err := client.Invoke("DescribeBandwidthPackages", args, response)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return response.BandwidthPackages.BandwidthPackage, err return response.BandwidthPackages.BandwidthPackage, err
} }
@ -171,20 +187,12 @@ type DeleteBandwidthPackageResponse struct {
common.Response common.Response
} }
func DeleteBandwidthPackage(client *ecs.Client, args *DeleteBandwidthPackageArgs) error { func (client *Client) DeleteBandwidthPackage(args *DeleteBandwidthPackageArgs) error {
response := DeleteBandwidthPackageResponse{} response := DeleteBandwidthPackageResponse{}
err := client.Invoke("DeleteBandwidthPackage", args, &response) err := client.Invoke("DeleteBandwidthPackage", args, &response)
return err return err
} }
type DescribeSnatTableEntriesArgs struct {
RegionId common.Region
}
func DescribeSnatTableEntries(client *ecs.Client, args *DescribeSnatTableEntriesArgs) {
}
type NatGatewaySpec string type NatGatewaySpec string
const ( const (

View File

@ -33,6 +33,7 @@ type DescribeSecurityGroupAttributeArgs struct {
SecurityGroupId string SecurityGroupId string
RegionId common.Region RegionId common.Region
NicType NicType //enum for internet (default) |intranet NicType NicType //enum for internet (default) |intranet
Direction string // enum ingress egress
} }
// //

View File

@ -0,0 +1,95 @@
package ecs
import "github.com/denverdino/aliyungo/common"
type CreateSnatEntryArgs struct {
RegionId common.Region
SnatTableId string
SourceVSwitchId string
SnatIp string
}
type CreateSnatEntryResponse struct {
common.Response
SnatEntryId string
}
type SnatEntrySetType struct {
RegionId common.Region
SnatEntryId string
SnatIp string
SnatTableId string
SourceCIDR string
SourceVSwitchId string
Status string
}
type DescribeSnatTableEntriesArgs struct {
RegionId common.Region
SnatTableId string
common.Pagination
}
type DescribeSnatTableEntriesResponse struct {
common.Response
common.PaginationResult
SnatTableEntries struct {
SnatTableEntry []SnatEntrySetType
}
}
type ModifySnatEntryArgs struct {
RegionId common.Region
SnatTableId string
SnatEntryId string
SnatIp string
}
type ModifySnatEntryResponse struct {
common.Response
}
type DeleteSnatEntryArgs struct {
RegionId common.Region
SnatTableId string
SnatEntryId string
}
type DeleteSnatEntryResponse struct {
common.Response
}
func (client *Client) CreateSnatEntry(args *CreateSnatEntryArgs) (resp *CreateSnatEntryResponse, err error) {
response := CreateSnatEntryResponse{}
err = client.Invoke("CreateSnatEntry", args, &response)
if err != nil {
return nil, err
}
return &response, err
}
func (client *Client) DescribeSnatTableEntries(args *DescribeSnatTableEntriesArgs) (snatTableEntries []SnatEntrySetType,
pagination *common.PaginationResult, err error) {
args.Validate()
response := DescribeSnatTableEntriesResponse{}
err = client.Invoke("DescribeSnatTableEntries", args, &response)
if err != nil {
return nil, nil, err
}
return response.SnatTableEntries.SnatTableEntry, &response.PaginationResult, nil
}
func (client *Client) ModifySnatEntry(args *ModifySnatEntryArgs) error {
response := ModifySnatEntryResponse{}
return client.Invoke("ModifySnatEntry", args, &response)
}
func (client *Client) DeleteSnatEntry(args *DeleteSnatEntryArgs) error {
response := DeleteSnatEntryResponse{}
err := client.Invoke("DeleteSnatEntry", args, &response)
return err
}

48
vendor/github.com/denverdino/aliyungo/rds/client.go generated vendored Normal file
View File

@ -0,0 +1,48 @@
package rds
import (
"github.com/denverdino/aliyungo/common"
"os"
)
type Client struct {
common.Client
}
const (
// ECSDefaultEndpoint is the default API endpoint of RDS services
RDSDefaultEndpoint = "https://rds.aliyuncs.com"
RDSAPIVersion = "2014-08-15"
RDSServiceCode = "rds"
)
// NewClient creates a new instance of RDS client
func NewClient(accessKeyId, accessKeySecret string) *Client {
endpoint := os.Getenv("RDS_ENDPOINT")
if endpoint == "" {
endpoint = RDSDefaultEndpoint
}
return NewClientWithEndpoint(endpoint, accessKeyId, accessKeySecret)
}
func NewClientWithEndpoint(endpoint string, accessKeyId, accessKeySecret string) *Client {
client := &Client{}
client.Init(endpoint, RDSAPIVersion, accessKeyId, accessKeySecret)
return client
}
func NewRDSClient(accessKeyId, accessKeySecret string, regionID common.Region) *Client {
endpoint := os.Getenv("RDS_ENDPOINT")
if endpoint == "" {
endpoint = RDSDefaultEndpoint
}
return NewClientWithRegion(endpoint, accessKeyId, accessKeySecret, regionID)
}
func NewClientWithRegion(endpoint string, accessKeyId, accessKeySecret string, regionID common.Region) *Client {
client := &Client{}
client.NewInit(endpoint, RDSAPIVersion, accessKeyId, accessKeySecret, RDSServiceCode, regionID)
return client
}

843
vendor/github.com/denverdino/aliyungo/rds/instances.go generated vendored Normal file
View File

@ -0,0 +1,843 @@
package rds
import (
"github.com/denverdino/aliyungo/common"
"time"
)
type DBInstanceIPArray struct {
SecurityIps string
DBInstanceIPArrayName string
DBInstanceIPArrayAttribute string
}
// ref: https://help.aliyun.com/document_detail/26242.html
type ModifySecurityIpsArgs struct {
DBInstanceId string
DBInstanceIPArray
}
func (client *Client) ModifySecurityIps(args *ModifySecurityIpsArgs) (resp common.Response, err error) {
response := common.Response{}
err = client.Invoke("ModifySecurityIps", args, &response)
return response, err
}
type DescribeDBInstanceIPsArgs struct {
DBInstanceId string
}
type DBInstanceIPList struct {
DBInstanceIPArrayName string
DBInstanceIPArrayAttribute string
SecurityIPList string
}
type DescribeDBInstanceIPsResponse struct {
common.Response
Items struct {
DBInstanceIPArray []DBInstanceIPList
}
}
// DescribeDBInstanceIPArrayList describe security ips
//
// You can read doc at https://help.aliyun.com/document_detail/26241.html?spm=5176.doc26242.6.715.d9pxvr
func (client *Client) DescribeDBInstanceIPs(args *DescribeDBInstanceIPsArgs) (resp *DescribeDBInstanceIPsResponse, err error) {
response := DescribeDBInstanceIPsResponse{}
err = client.Invoke("DescribeDBInstanceIPArrayList", args, &response)
if err != nil {
return nil, err
}
return &response, nil
}
// InstanceStatus represents instance status
type InstanceStatus string
// Constants of InstanceStatus
const (
Creating = InstanceStatus("Creating") // For backward compatability
Running = InstanceStatus("Running")
Deleting = InstanceStatus("Deleting")
Rebooting = InstanceStatus("Rebooting")
Restoring = InstanceStatus("Restoring")
Importing = InstanceStatus("Importing")
DBInstanceNetTypeChanging = InstanceStatus("DBInstanceNetTypeChanging")
)
type DBPayType string
const (
Prepaid = DBPayType("Prepaid")
Postpaid = DBPayType("Postpaid")
)
type CommodityCode string
const (
Rds = CommodityCode("rds")
Bards = CommodityCode("bards")
Rords = CommodityCode("rords")
)
type Engine string
const (
MySQL = Engine("MySQL")
SQLServer = Engine("SQLServer")
PPAS = Engine("PPAS")
PG = Engine("PG")
)
type ConnectionMode string
const (
Performance = ConnectionMode("Performance")
Safty = ConnectionMode("Safty")
)
// default resource value for create order
const DefaultResource = "buy"
type CreateOrderArgs struct {
CommodityCode CommodityCode
RegionId common.Region
ZoneId string
Engine Engine
EngineVersion string
PayType DBPayType
DBInstanceClass string
DBInstanceStorage int
DBInstanceNetType common.NetType
InstanceNetworkType common.NetworkType
VPCId string
VSwitchId string
UsedTime int
TimeType common.TimeType
Quantity int
InstanceUsedType string
Resource string
AutoPay string
AutoRenew string
BackupId string
RestoreTime string
SecurityIPList string
BusinessInfo string
}
type CreateOrderResponse struct {
common.Response
DBInstanceId string
OrderId int
}
// CreateOrder create db instance order
// you can read doc at http://docs.alibaba-inc.com/pages/viewpage.action?pageId=259349053
func (client *Client) CreateOrder(args *CreateOrderArgs) (resp CreateOrderResponse, err error) {
response := CreateOrderResponse{}
err = client.Invoke("CreateOrder", args, &response)
return response, err
}
type DescribeDBInstancesArgs struct {
DBInstanceId string
}
type DescribeDBInstanceAttributeResponse struct {
common.Response
Items struct {
DBInstanceAttribute []DBInstanceAttribute
}
}
type DBInstanceAttribute struct {
DBInstanceId string
PayType DBPayType
DBInstanceType string
InstanceNetworkType string
ConnectionMode string
RegionId string
ZoneId string
ConnectionString string
Port string
Engine Engine
EngineVersion string
DBInstanceClass string
DBInstanceMemory int64
DBInstanceStorage int
DBInstanceNetType string
DBInstanceStatus InstanceStatus
DBInstanceDescription string
LockMode string
LockReason string
DBMaxQuantity int
AccountMaxQuantity int
CreationTime string
ExpireTime string
MaintainTime string
AvailabilityValue string
MaxIOPS int
MaxConnections int
MasterInstanceId string
IncrementSourceDBInstanceId string
GuardDBInstanceId string
TempDBInstanceId string
ReadOnlyDBInstanceIds ReadOnlyDBInstanceIds
SecurityIPList string
}
type ReadOnlyDBInstanceIds struct {
ReadOnlyDBInstanceId []string
}
// DescribeDBInstanceAttribute describes db instance
//
// You can read doc at https://help.aliyun.com/document_detail/26231.html?spm=5176.doc26228.6.702.uhzm31
func (client *Client) DescribeDBInstanceAttribute(args *DescribeDBInstancesArgs) (resp *DescribeDBInstanceAttributeResponse, err error) {
response := DescribeDBInstanceAttributeResponse{}
err = client.Invoke("DescribeDBInstanceAttribute", args, &response)
if err == nil {
return &response, nil
}
return nil, err
}
type DescribeDatabasesArgs struct {
DBInstanceId string
DBName string
DBStatus InstanceStatus
}
type DescribeDatabasesResponse struct {
common.Response
Databases struct {
Database []Database
}
}
type Database struct {
DBName string
DBInstanceId string
Engine string
DBStatus InstanceStatus
CharacterSetName InstanceStatus
DBDescription InstanceStatus
Account InstanceStatus
AccountPrivilege InstanceStatus
Accounts struct {
AccountPrivilegeInfo []AccountPrivilegeInfo
}
}
type AccountPrivilegeInfo struct {
Account string
AccountPrivilege string
}
// DescribeDatabases describes db database
//
// You can read doc at https://help.aliyun.com/document_detail/26260.html?spm=5176.doc26258.6.732.gCx1a3
func (client *Client) DescribeDatabases(args *DescribeDatabasesArgs) (resp *DescribeDatabasesResponse, err error) {
response := DescribeDatabasesResponse{}
err = client.Invoke("DescribeDatabases", args, &response)
if err == nil {
return &response, nil
}
return nil, err
}
type DescribeAccountsArgs struct {
DBInstanceId string
AccountName string
}
type DescribeAccountsResponse struct {
common.Response
Accounts struct {
DBInstanceAccount []DBInstanceAccount
}
}
type DBInstanceAccount struct {
DBInstanceId string
AccountName string
AccountStatus AccountStatus
AccountDescription string
DatabasePrivileges struct {
DatabasePrivilege []DatabasePrivilege
}
}
type AccountStatus string
const (
Unavailable = AccountStatus("Unavailable")
Available = AccountStatus("Available")
)
type DatabasePrivilege struct {
DBName string
AccountPrivilege AccountPrivilege
}
// DescribeAccounts describes db accounts
//
// You can read doc at https://help.aliyun.com/document_detail/26265.html?spm=5176.doc26266.6.739.UjtjaI
func (client *Client) DescribeAccounts(args *DescribeAccountsArgs) (resp *DescribeAccountsResponse, err error) {
response := DescribeAccountsResponse{}
err = client.Invoke("DescribeAccounts", args, &response)
if err == nil {
return &response, nil
}
return nil, err
}
// Default timeout value for WaitForInstance method
const InstanceDefaultTimeout = 120
const DefaultWaitForInterval = 10
// WaitForInstance waits for instance to given status
func (client *Client) WaitForInstance(instanceId string, status InstanceStatus, timeout int) error {
if timeout <= 0 {
timeout = InstanceDefaultTimeout
}
for {
args := DescribeDBInstancesArgs{
DBInstanceId: instanceId,
}
resp, err := client.DescribeDBInstanceAttribute(&args)
if err != nil {
return err
}
if timeout <= 0 {
return common.GetClientErrorFromString("Timeout")
}
timeout = timeout - DefaultWaitForInterval
time.Sleep(DefaultWaitForInterval * time.Second)
if len(resp.Items.DBInstanceAttribute) < 1 {
continue
}
instance := resp.Items.DBInstanceAttribute[0]
if instance.DBInstanceStatus == status {
break
}
}
return nil
}
func (client *Client) WaitForAllDatabase(instanceId string, databaseNames []string, status InstanceStatus, timeout int) error {
if timeout <= 0 {
timeout = InstanceDefaultTimeout
}
for {
args := DescribeDatabasesArgs{
DBInstanceId: instanceId,
}
resp, err := client.DescribeDatabases(&args)
if err != nil {
return err
}
if timeout <= 0 {
return common.GetClientErrorFromString("Timeout")
}
timeout = timeout - DefaultWaitForInterval
time.Sleep(DefaultWaitForInterval * time.Second)
ready := 0
for _, nm := range databaseNames {
for _, db := range resp.Databases.Database {
if db.DBName == nm {
if db.DBStatus == status {
ready++
break
}
}
}
}
if ready == len(databaseNames) {
break
}
}
return nil
}
func (client *Client) WaitForAccount(instanceId string, accountName string, status AccountStatus, timeout int) error {
if timeout <= 0 {
timeout = InstanceDefaultTimeout
}
for {
args := DescribeAccountsArgs{
DBInstanceId: instanceId,
AccountName: accountName,
}
resp, err := client.DescribeAccounts(&args)
if err != nil {
return err
}
accs := resp.Accounts.DBInstanceAccount
if timeout <= 0 {
return common.GetClientErrorFromString("Timeout")
}
timeout = timeout - DefaultWaitForInterval
time.Sleep(DefaultWaitForInterval * time.Second)
if len(accs) < 1 {
continue
}
acc := accs[0]
if acc.AccountStatus == status {
break
}
}
return nil
}
func (client *Client) WaitForPublicConnection(instanceId string, timeout int) error {
if timeout <= 0 {
timeout = InstanceDefaultTimeout
}
for {
args := DescribeDBInstanceNetInfoArgs{
DBInstanceId: instanceId,
}
resp, err := client.DescribeDBInstanceNetInfo(&args)
if err != nil {
return err
}
if timeout <= 0 {
return common.GetClientErrorFromString("Timeout")
}
timeout = timeout - DefaultWaitForInterval
time.Sleep(DefaultWaitForInterval * time.Second)
ready := false
for _, info := range resp.DBInstanceNetInfos.DBInstanceNetInfo {
if info.IPType == Public {
ready = true
}
}
if ready {
break
}
}
return nil
}
func (client *Client) WaitForAccountPrivilege(instanceId, accountName, dbName string, privilege AccountPrivilege, timeout int) error {
if timeout <= 0 {
timeout = InstanceDefaultTimeout
}
for {
args := DescribeAccountsArgs{
DBInstanceId: instanceId,
AccountName: accountName,
}
resp, err := client.DescribeAccounts(&args)
if err != nil {
return err
}
accs := resp.Accounts.DBInstanceAccount
if timeout <= 0 {
return common.GetClientErrorFromString("Timeout")
}
timeout = timeout - DefaultWaitForInterval
time.Sleep(DefaultWaitForInterval * time.Second)
if len(accs) < 1 {
continue
}
acc := accs[0]
ready := false
for _, dp := range acc.DatabasePrivileges.DatabasePrivilege {
if dp.DBName == dbName && dp.AccountPrivilege == privilege {
ready = true
}
}
if ready {
break
}
}
return nil
}
type DeleteDBInstanceArgs struct {
DBInstanceId string
}
type DeleteDBInstanceResponse struct {
common.Response
}
// DeleteInstance deletes db instance
//
// You can read doc at https://help.aliyun.com/document_detail/26229.html?spm=5176.doc26315.6.700.7SmyAT
func (client *Client) DeleteInstance(instanceId string) error {
args := DeleteDBInstanceArgs{DBInstanceId: instanceId}
response := DeleteDBInstanceResponse{}
err := client.Invoke("DeleteDBInstance", &args, &response)
return err
}
type DeleteDatabaseArgs struct {
DBInstanceId string
DBName string
}
type DeleteDatabaseResponse struct {
common.Response
}
// DeleteInstance deletes database
//
// You can read doc at https://help.aliyun.com/document_detail/26259.html?spm=5176.doc26260.6.731.Abjwne
func (client *Client) DeleteDatabase(instanceId, dbName string) error {
args := DeleteDatabaseArgs{
DBInstanceId: instanceId,
DBName: dbName,
}
response := DeleteDatabaseResponse{}
err := client.Invoke("DeleteDatabase", &args, &response)
return err
}
type DescribeRegionsArgs struct {
}
type DescribeRegionsResponse struct {
Regions struct {
RDSRegion []RDSRegion
}
}
type RDSRegion struct {
RegionId string
ZoneId string
}
// DescribeRegions describe rds regions
//
// You can read doc at https://help.aliyun.com/document_detail/26243.html?spm=5176.doc26244.6.715.OSNUa8
func (client *Client) DescribeRegions() (resp *DescribeRegionsResponse, err error) {
args := DescribeRegionsArgs{}
response := DescribeRegionsResponse{}
err = client.Invoke("DescribeRegions", &args, &response)
if err != nil {
return nil, err
}
return &response, nil
}
type CreateDatabaseResponse struct {
common.Response
}
type CreateDatabaseArgs struct {
DBInstanceId string
DBName string
CharacterSetName string
DBDescription string
}
// CreateDatabase create rds database
//
// You can read doc at https://help.aliyun.com/document_detail/26243.html?spm=5176.doc26244.6.715.OSNUa8
func (client *Client) CreateDatabase(args *CreateDatabaseArgs) (resp *CreateDatabaseResponse, err error) {
response := CreateDatabaseResponse{}
err = client.Invoke("CreateDatabase", args, &response)
if err != nil {
return nil, err
}
return &response, nil
}
type CreateAccountResponse struct {
common.Response
}
type AccountType struct {
Normal string
Super string
}
type CreateAccountArgs struct {
DBInstanceId string
AccountName string
AccountPassword string
AccountType AccountType
AccountDescription string
}
// CreateAccount create rds account
//
// You can read doc at https://help.aliyun.com/document_detail/26263.html?spm=5176.doc26240.6.736.ZDihok
func (client *Client) CreateAccount(args *CreateAccountArgs) (resp *CreateAccountResponse, err error) {
response := CreateAccountResponse{}
err = client.Invoke("CreateAccount", args, &response)
if err != nil {
return nil, err
}
return &response, nil
}
type DeleteAccountResponse struct {
common.Response
}
type DeleteAccountArgs struct {
DBInstanceId string
AccountName string
}
// DeleteAccount delete account
//
// You can read doc at https://help.aliyun.com/document_detail/26264.html?spm=5176.doc26269.6.737.CvlZp6
func (client *Client) DeleteAccount(instanceId, accountName string) (resp *DeleteAccountResponse, err error) {
args := DeleteAccountArgs{
DBInstanceId: instanceId,
AccountName: accountName,
}
response := DeleteAccountResponse{}
err = client.Invoke("DeleteAccount", &args, &response)
if err != nil {
return nil, err
}
return &response, nil
}
type GrantAccountPrivilegeResponse struct {
common.Response
}
type GrantAccountPrivilegeArgs struct {
DBInstanceId string
AccountName string
DBName string
AccountPrivilege AccountPrivilege
}
type AccountPrivilege string
const (
ReadOnly = AccountPrivilege("ReadOnly")
ReadWrite = AccountPrivilege("ReadWrite")
)
// GrantAccountPrivilege grant database privilege to account
//
// You can read doc at https://help.aliyun.com/document_detail/26266.html?spm=5176.doc26264.6.739.o2y01n
func (client *Client) GrantAccountPrivilege(args *GrantAccountPrivilegeArgs) (resp *GrantAccountPrivilegeResponse, err error) {
response := GrantAccountPrivilegeResponse{}
err = client.Invoke("GrantAccountPrivilege", args, &response)
if err != nil {
return nil, err
}
return &response, nil
}
type AllocateInstancePublicConnectionResponse struct {
common.Response
}
type AllocateInstancePublicConnectionArgs struct {
DBInstanceId string
ConnectionStringPrefix string
Port string
}
// AllocateInstancePublicConnection allocate public connection
//
// You can read doc at https://help.aliyun.com/document_detail/26234.html?spm=5176.doc26265.6.708.PdsJnL
func (client *Client) AllocateInstancePublicConnection(args *AllocateInstancePublicConnectionArgs) (resp *AllocateInstancePublicConnectionResponse, err error) {
response := AllocateInstancePublicConnectionResponse{}
err = client.Invoke("AllocateInstancePublicConnection", args, &response)
if err != nil {
return nil, err
}
return &response, nil
}
type DescribeDBInstanceNetInfoArgs struct {
DBInstanceId string
}
type DescribeDBInstanceNetInfoResponse struct {
common.Response
InstanceNetworkType string
DBInstanceNetInfos struct {
DBInstanceNetInfo []DBInstanceNetInfo
}
}
type DBInstanceNetInfo struct {
ConnectionString string
IPAddress string
Port string
VPCId string
VSwitchId string
IPType IPType
}
type IPType string
const (
Inner = IPType("Inner")
Private = IPType("Private")
Public = IPType("Public")
)
// DescribeDBInstanceNetInfo describe rds net info
//
// You can read doc at https://help.aliyun.com/document_detail/26237.html?spm=5176.doc26234.6.711.vHOktx
func (client *Client) DescribeDBInstanceNetInfo(args *DescribeDBInstanceNetInfoArgs) (resp *DescribeDBInstanceNetInfoResponse, err error) {
response := DescribeDBInstanceNetInfoResponse{}
err = client.Invoke("DescribeDBInstanceNetInfo", args, &response)
if err != nil {
return nil, err
}
return &response, nil
}
type BackupPolicy struct {
PreferredBackupTime string // HH:mmZ - HH:mm Z
PreferredBackupPeriod string // Monday - Sunday
BackupRetentionPeriod int // 7 - 730
BackupLog string // enum Enable | Disabled
LogBackupRetentionPeriod string
}
type ModifyBackupPolicyArgs struct {
DBInstanceId string
BackupPolicy
}
type ModifyBackupPolicyResponse struct {
common.Response
}
// ModifyBackupPolicy modify backup policy
//
// You can read doc at https://help.aliyun.com/document_detail/26276.html?spm=5176.doc26250.6.751.KOew21
func (client *Client) ModifyBackupPolicy(args *ModifyBackupPolicyArgs) (resp *ModifyBackupPolicyResponse, err error) {
response := ModifyBackupPolicyResponse{}
err = client.Invoke("ModifyBackupPolicy", args, &response)
if err != nil {
return nil, err
}
return &response, nil
}
type DescribeBackupPolicyArgs struct {
DBInstanceId string
}
type DescribeBackupPolicyResponse struct {
common.Response
BackupPolicy
}
// DescribeBackupPolicy describe backup policy
//
// You can read doc at https://help.aliyun.com/document_detail/26275.html?spm=5176.doc26276.6.750.CUqjDn
func (client *Client) DescribeBackupPolicy(args *DescribeBackupPolicyArgs) (resp *DescribeBackupPolicyResponse, err error) {
response := DescribeBackupPolicyResponse{}
err = client.Invoke("DescribeBackupPolicy", args, &response)
if err != nil {
return nil, err
}
return &response, nil
}
type ModifyDBInstanceSpecArgs struct {
DBInstanceId string
PayType DBPayType
DBInstanceClass string
DBInstanceStorage string
}
type ModifyDBInstanceSpecResponse struct {
common.Response
}
// ModifyDBInstanceSpec modify db instance spec
//
// You can read doc at https://help.aliyun.com/document_detail/26233.html?spm=5176.doc26258.6.707.2QOLrM
func (client *Client) ModifyDBInstanceSpec(args *ModifyDBInstanceSpecArgs) (resp *ModifyDBInstanceSpecResponse, err error) {
response := ModifyDBInstanceSpecResponse{}
err = client.Invoke("ModifyDBInstanceSpec", args, &response)
if err != nil {
return nil, err
}
return &response, nil
}
var WEEK_ENUM = []string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}
var BACKUP_TIME = []string{
"00:00Z-01:00Z", "01:00Z-02:00Z", "02:00Z-03:00Z", "03:00Z-04:00Z", "04:00Z-05:00Z",
"05:00Z-06:00Z", "06:00Z-07:00Z", "07:00Z-08:00Z", "08:00Z-09:00Z", "09:00Z-10:00Z",
"10:00Z-11:00Z", "11:00Z-12:00Z", "12:00Z-13:00Z", "13:00Z-14:00Z", "14:00Z-15:00Z",
"15:00Z-16:00Z", "16:00Z-17:00Z", "17:00Z-18:00Z", "18:00Z-19:00Z", "19:00Z-20:00Z",
"20:00Z-21:00Z", "21:00Z-22:00Z", "22:00Z-23:00Z", "23:00Z-24:00Z",
}
var CHARACTER_SET_NAME = []string{
"utf8", "gbk", "latin1", "utf8mb4",
"Chinese_PRC_CI_AS", "Chinese_PRC_CS_AS", "SQL_Latin1_General_CP1_CI_AS", "SQL_Latin1_General_CP1_CS_AS", "Chinese_PRC_BIN",
}

View File

@ -0,0 +1,50 @@
package rds
import (
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/util"
)
type DescribeDBInstancePerformanceArgs struct {
DBInstanceId string
key string
StartTime string
EndTime string
}
type PerformanceValueType struct {
Value string
Date util.ISO6801Time
}
type PerformanceKeyType struct {
Key string
Unit string
ValueFormat string
Values struct {
PerformanceValue []PerformanceValueType
}
}
type DescribeDBInstancePerformanceResponse struct {
common.Response
DBInstanceId string
Engine string
StartTime util.ISO6801Time
EndTime util.ISO6801Time
PerformanceKeys struct {
PerformanceKey []PerformanceKeyType
}
}
func (client *DescribeDBInstancePerformanceArgs) Setkey(key string) {
client.key = key
}
func (client *Client) DescribeDBInstancePerformance(args *DescribeDBInstancePerformanceArgs) (resp DescribeDBInstancePerformanceResponse, err error) {
response := DescribeDBInstancePerformanceResponse{}
err = client.Invoke("DescribeDBInstancePerformance", args, &response)
return response, err
}

View File

@ -1,8 +1,9 @@
package slb package slb
import ( import (
"github.com/denverdino/aliyungo/common"
"os" "os"
"github.com/denverdino/aliyungo/common"
) )
type Client struct { type Client struct {
@ -13,6 +14,8 @@ const (
// SLBDefaultEndpoint is the default API endpoint of SLB services // SLBDefaultEndpoint is the default API endpoint of SLB services
SLBDefaultEndpoint = "https://slb.aliyuncs.com" SLBDefaultEndpoint = "https://slb.aliyuncs.com"
SLBAPIVersion = "2014-05-15" SLBAPIVersion = "2014-05-15"
SLBServiceCode = "slb"
) )
// NewClient creates a new instance of ECS client // NewClient creates a new instance of ECS client
@ -29,3 +32,18 @@ func NewClientWithEndpoint(endpoint string, accessKeyId, accessKeySecret string)
client.Init(endpoint, SLBAPIVersion, accessKeyId, accessKeySecret) client.Init(endpoint, SLBAPIVersion, accessKeyId, accessKeySecret)
return client return client
} }
func NewSLBClient(accessKeyId, accessKeySecret string, regionID common.Region) *Client {
endpoint := os.Getenv("SLB_ENDPOINT")
if endpoint == "" {
endpoint = SLBDefaultEndpoint
}
return NewClientWithRegion(endpoint, accessKeyId, accessKeySecret, regionID)
}
func NewClientWithRegion(endpoint string, accessKeyId, accessKeySecret string, regionID common.Region) *Client {
client := &Client{}
client.NewInit(endpoint, SLBAPIVersion, accessKeyId, accessKeySecret, SLBServiceCode, regionID)
return client
}

View File

@ -138,22 +138,22 @@ const (
) )
type TCPListenerType struct { type TCPListenerType struct {
LoadBalancerId string LoadBalancerId string
ListenerPort int ListenerPort int
BackendServerPort int BackendServerPort int
Bandwidth int Bandwidth int
Scheduler SchedulerType Scheduler SchedulerType
PersistenceTimeout int PersistenceTimeout int
HealthCheckType HealthCheckType HealthCheckType HealthCheckType
HealthCheckDomain string HealthCheckDomain string
HealthCheckURI string HealthCheckURI string
HealthCheckConnectPort int HealthCheckConnectPort int
HealthyThreshold int HealthyThreshold int
UnhealthyThreshold int UnhealthyThreshold int
HealthCheckTimeout int HealthCheckConnectTimeout int
HealthCheckInterval int HealthCheckInterval int
HealthCheckHttpCode HealthCheckHttpCodeType HealthCheckHttpCode HealthCheckHttpCodeType
VServerGroupId string VServerGroupId string
} }
type CreateLoadBalancerTCPListenerArgs TCPListenerType type CreateLoadBalancerTCPListenerArgs TCPListenerType
@ -168,18 +168,18 @@ func (client *Client) CreateLoadBalancerTCPListener(args *CreateLoadBalancerTCPL
} }
type UDPListenerType struct { type UDPListenerType struct {
LoadBalancerId string LoadBalancerId string
ListenerPort int ListenerPort int
BackendServerPort int BackendServerPort int
Bandwidth int Bandwidth int
Scheduler SchedulerType Scheduler SchedulerType
PersistenceTimeout int PersistenceTimeout int
HealthCheckConnectPort int HealthCheckConnectPort int
HealthyThreshold int HealthyThreshold int
UnhealthyThreshold int UnhealthyThreshold int
HealthCheckTimeout int HealthCheckConnectTimeout int
HealthCheckInterval int HealthCheckInterval int
VServerGroupId string VServerGroupId string
} }
type CreateLoadBalancerUDPListenerArgs UDPListenerType type CreateLoadBalancerUDPListenerArgs UDPListenerType

126
vendor/github.com/denverdino/aliyungo/slb/rules.go generated vendored Normal file
View File

@ -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 `json:",omitempty"`
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
}

View File

@ -23,7 +23,6 @@ type AddBackendServersResponse struct {
type SetBackendServersResponse AddBackendServersResponse type SetBackendServersResponse AddBackendServersResponse
// SetBackendServers set weight of backend servers // SetBackendServers set weight of backend servers
func (client *Client) SetBackendServers(loadBalancerId string, backendServers []BackendServerType) (result []BackendServerType, err error) { func (client *Client) SetBackendServers(loadBalancerId string, backendServers []BackendServerType) (result []BackendServerType, err error) {
@ -42,7 +41,6 @@ func (client *Client) SetBackendServers(loadBalancerId string, backendServers []
return response.BackendServers.BackendServer, err return response.BackendServers.BackendServer, err
} }
// AddBackendServers Add backend servers // AddBackendServers Add backend servers
// //
// You can read doc at http://docs.aliyun.com/#/pub/slb/api-reference/api-related-backendserver&AddBackendServers // You can read doc at http://docs.aliyun.com/#/pub/slb/api-reference/api-related-backendserver&AddBackendServers

28
vendor/vendor.json vendored
View File

@ -1292,28 +1292,34 @@
"revisionTime": "2016-10-29T20:57:26Z" "revisionTime": "2016-10-29T20:57:26Z"
}, },
{ {
"checksumSHA1": "ADySw3nBHyzEHB6afBSeVRN2A4g=", "checksumSHA1": "SdiAYZOqWQ60ifRUHLwLiDMKMYA=",
"path": "github.com/denverdino/aliyungo/common", "path": "github.com/denverdino/aliyungo/common",
"revision": "d123f5d1fa71b211b70b2e9b56a62da21076884a", "revision": "c4c75afbf7ea86e66672c1b6ed981385b4ad5ec2",
"revisionTime": "2017-01-17T10:57:15Z" "revisionTime": "2017-03-21T07:55:32Z"
}, },
{ {
"checksumSHA1": "9ZY3RlumKp5DAMfL08YwMoOOT2o=", "checksumSHA1": "UVYu5rvfoXgJnIpUyGcaovMvpms=",
"path": "github.com/denverdino/aliyungo/ecs", "path": "github.com/denverdino/aliyungo/ecs",
"revision": "d123f5d1fa71b211b70b2e9b56a62da21076884a", "revision": "c4c75afbf7ea86e66672c1b6ed981385b4ad5ec2",
"revisionTime": "2017-01-17T10:57:15Z" "revisionTime": "2017-03-21T07:55:32Z"
}, },
{ {
"checksumSHA1": "QlA7zv05k7HWeR3tg4uHqIlFcg8=", "checksumSHA1": "riQMe2AR7qkLRkQ/MSr8gQp3zL4=",
"path": "github.com/denverdino/aliyungo/rds",
"revision": "c4c75afbf7ea86e66672c1b6ed981385b4ad5ec2",
"revisionTime": "2017-03-21T07:55:32Z"
},
{
"checksumSHA1": "2g6VZONB51rul5YuSBvngH6u4A0=",
"path": "github.com/denverdino/aliyungo/slb", "path": "github.com/denverdino/aliyungo/slb",
"revision": "d123f5d1fa71b211b70b2e9b56a62da21076884a", "revision": "c4c75afbf7ea86e66672c1b6ed981385b4ad5ec2",
"revisionTime": "2017-01-17T10:57:15Z" "revisionTime": "2017-03-21T07:55:32Z"
}, },
{ {
"checksumSHA1": "Lp0KtT7ycgq31ox3Uzhpxyw0U+Y=", "checksumSHA1": "Lp0KtT7ycgq31ox3Uzhpxyw0U+Y=",
"path": "github.com/denverdino/aliyungo/util", "path": "github.com/denverdino/aliyungo/util",
"revision": "d123f5d1fa71b211b70b2e9b56a62da21076884a", "revision": "c4c75afbf7ea86e66672c1b6ed981385b4ad5ec2",
"revisionTime": "2017-01-17T10:57:15Z" "revisionTime": "2017-03-21T07:55:32Z"
}, },
{ {
"checksumSHA1": "yDQQpeUxwqB3C+4opweg6znWJQk=", "checksumSHA1": "yDQQpeUxwqB3C+4opweg6znWJQk=",

View File

@ -0,0 +1,106 @@
---
layout: "alicloud"
page_title: "Alicloud: alicloud_db_instance"
sidebar_current: "docs-alicloud-resource-db-instance"
description: |-
Provides an RDS instance resource.
---
# 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
databases.
## Example Usage
```
resource "alicloud_db_instance" "default" {
commodity_code = "rds"
engine = "MySQL"
engine_version = "5.6"
db_instance_class = "rds.mysql.t1.small"
db_instance_storage = "10"
db_instance_net_type = "Intranet"
}
```
## Argument Reference
The following arguments are supported:
* `engine` - (Required) Database type. Value options: MySQL, SQLServer, PostgreSQL, and PPAS.
* `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:
- [5, 2000] for MySQL/PostgreSQL/PPAS HA dual node edition;
- [20,1000] for MySQL 5.7 basic single node edition;
- [10, 2000] for SQL Server 2008R2;
- [20,2000] for SQL Server 2012 basic single node edition
Increase progressively at a rate of 5 GB. The unit is GB. For details, see [Instance type table](https://intl.aliyun.com/help/doc-detail/26312.htm?spm=a3c0i.o26228en.a3.3.bRUHF3).
* `instance_charge_type` - (Optional) Valid values are `Prepaid`, `Postpaid`, The default is `Postpaid`.
* `period` - (Optional) The time that you have bought the resource, in month. Only valid when instance_charge_type is set as `PrePaid`. Value range [1, 12].
* `zone_id` - (Optional) Selected zone to create database instance. You cannot set the ZoneId parameter if the MultiAZ parameter is set to true.
* `multi_az` - (Optional) Specifies if the database instance is a multiple Availability Zone deployment.
* `db_instance_net_type` - (Optional) Network connection type of an instance. Internet: public network; Intranet: private network
* `allocate_public_connection` - (Optional) If set to true will applies for an Internet connection string of an instance.
* `instance_network_type` - (Optional) VPC: VPC instance; Classic: classic instance. If no value is specified, a classic instance will be created by default.
* `vswitch_id` - (Optional) The virtual switch ID to launch in VPC. If you want to create instances in VPC network, this parameter must be set.
* `master_user_name` - (Optional) The master user name for the database instance. Operation account requiring a uniqueness check. It may consist of lower case letters, numbers and underlines, and must start with a letter and have no more than 16 characters.
* `master_user_password` - (Optional) The master password for the database instance. Operation password. It may consist of letters, digits, or underlines, with a length of 6 to 32 characters.
* `preferred_backup_period` - (Optional) Backup period. Values: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, and Sunday.
* `preferred_backup_time` - (Optional) Backup time, in the format ofHH:mmZ- HH:mm Z.
* `backup_retention_period` - (Optional) Retention days of the backup (7 to 730 days). The default value is 7 days.
* `security_ips` - (Optional) List of IP addresses under the IP address white list array. The list contains up to 1,000 IP addresses, separated by commas. Supported formats include 0.0.0.0/0, 10.23.12.24 (IP), and 10.23.12.24/24 (Classless Inter-Domain Routing (CIDR) mode. /24 represents the length of the prefix in an IP address. The range of the prefix length is [1,32]).
* `db_mappings` - (Optional) Database mappings to attach to db instance. See [Block database](#block-database) below for details.
## Block database
The database mapping supports the following:
* `db_name` - (Required) Name of the database requiring a uniqueness check. It may consist of lower case letters, numbers and underlines, and must start with a letter and have no more than 64 characters.
* `character_set_name` - (Required) Character set. The value range is limited to the following:
- MySQL type:
+ utf8
+ gbk
+ latin1
+ utf8mb4 (included in versions 5.5 and 5.6).
- SQLServer type:
+ Chinese_PRC_CI_AS
+ Chinese_PRC_CS_AS
+ SQL_Latin1_General_CP1_CI_AS
+ SQL_Latin1_General_CP1_CS_AS
+ Chinese_PRC_BIN
* `db_description` - (Optional) Database description, which cannot exceed 256 characters. NOTE: It cannot begin with https://.
~> **NOTE:** We neither support modify any of database attribute, nor insert/remove item at the same time.
We recommend split to two separate operations.
## Attributes Reference
The following attributes are exported:
* `id` - The RDS instance ID.
* `instance_charge_type` - The instance charge type.
* `period` - The time that you have bought the resource.
* `engine` - Database type.
* `engine_version` - The database engine version.
* `db_instance_class` - The RDS instance class.
* `db_instance_storage` - The amount of allocated storage.
* `port` - The database port.
* `zone_id` - The zone ID of the DB instance.
* `db_instance_net_type` - Network connection type of an instance, `Internet` or `Intranet`.
* `instance_network_type` - The instance network type and it has two values: `vpc` and `classic`.
* `db_mappings` - Database mappings attached to db instance.
* `preferred_backup_period` - Backup period.
* `preferred_backup_time` - Backup time.
* `backup_retention_period` - Retention days of the backup.
* `security_ips` - Security ips of instance whitelist.
* `connections` - Views all the connection information of a specified instance.

View File

@ -54,16 +54,14 @@ resource "alicloud_slb" "vpc" {
The following arguments are supported: 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. * `image_id` - (Required) The Image to use for the instance.
* `instance_type` - (Required) The type of instance to start. * `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. * `io_optimized` - (Required) Valid values are `none`, `optimized`, If `optimized`, the launched ECS instance will be I/O optimized.
`security_group_ids` instead. * `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, * `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`. 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. * `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. * `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. * `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.
@ -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. * `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`. * `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]. * `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. * `tags` - (Optional) A mapping of tags to assign to the resource.
## Attributes Reference ## Attributes Reference