provider/alicloud: Add the function of replacing ecs instance's system disk (#15048)

* add replacing system disk function for ecs

* remove ForceNew of system_disk_size
This commit is contained in:
He Guimin 2017-06-05 16:27:49 +08:00 committed by Paul Stack
parent d6d559a6ab
commit 87562be855
17 changed files with 458 additions and 50 deletions

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=countHookAction hook_count_action.go"; DO NOT EDIT.
// Code generated by "stringer -type=countHookAction hook_count_action.go"; DO NOT EDIT
package local

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=OperationType operation_type.go"; DO NOT EDIT.
// Code generated by "stringer -type=OperationType operation_type.go"; DO NOT EDIT
package backend

View File

@ -114,7 +114,6 @@ func resourceAliyunInstance() *schema.Resource {
Type: schema.TypeInt,
Optional: true,
Computed: true,
ForceNew: true,
ValidateFunc: validateIntegerInRange(40, 500),
},
@ -365,12 +364,62 @@ func resourceAliyunInstanceUpdate(d *schema.ResourceData, meta interface{}) erro
d.SetPartial("tags")
}
imageUpdate := false
if d.HasChange("image_id") && !d.IsNewResource() {
log.Printf("[DEBUG] Replace instance system disk via changing image_id")
replaceSystemArgs := &ecs.ReplaceSystemDiskArgs{
InstanceId: d.Id(),
ImageId: d.Get("image_id").(string),
SystemDisk: ecs.SystemDiskType{
Size: d.Get("system_disk_size").(int),
},
}
if v, ok := d.GetOk("status"); ok && v.(string) != "" {
if ecs.InstanceStatus(d.Get("status").(string)) == ecs.Running {
log.Printf("[DEBUG] StopInstance before change system disk")
if err := conn.StopInstance(d.Id(), true); err != nil {
return fmt.Errorf("Force Stop Instance got an error: %#v", err)
}
if err := conn.WaitForInstance(d.Id(), ecs.Stopped, 60); err != nil {
return fmt.Errorf("WaitForInstance got error: %#v", err)
}
}
}
_, err := conn.ReplaceSystemDisk(replaceSystemArgs)
if err != nil {
return fmt.Errorf("Replace system disk got an error: %#v", err)
}
// Ensure instance's image has been replaced successfully.
timeout := ecs.InstanceDefaultTimeout
for {
instance, errDesc := conn.DescribeInstanceAttribute(d.Id())
if errDesc != nil {
return fmt.Errorf("Describe instance got an error: %#v", errDesc)
}
if instance.ImageId == d.Get("image_id") {
break
}
time.Sleep(ecs.DefaultWaitForInterval * time.Second)
timeout = timeout - ecs.DefaultWaitForInterval
if timeout <= 0 {
return common.GetClientErrorFromString("Timeout")
}
}
imageUpdate = true
d.SetPartial("system_disk_size")
d.SetPartial("image_id")
}
// Provider doesn't support change 'system_disk_size'separately.
if d.HasChange("system_disk_size") && !d.HasChange("image_id") {
return fmt.Errorf("Update resource failed. 'system_disk_size' isn't allowed to change separately. You can update it via renewing instance or replacing system disk.")
}
attributeUpdate := false
args := &ecs.ModifyInstanceAttributeArgs{
InstanceId: d.Id(),
}
if d.HasChange("instance_name") {
if d.HasChange("instance_name") && !d.IsNewResource() {
log.Printf("[DEBUG] ModifyInstanceAttribute instance_name")
d.SetPartial("instance_name")
args.InstanceName = d.Get("instance_name").(string)
@ -378,7 +427,7 @@ func resourceAliyunInstanceUpdate(d *schema.ResourceData, meta interface{}) erro
attributeUpdate = true
}
if d.HasChange("description") {
if d.HasChange("description") && !d.IsNewResource() {
log.Printf("[DEBUG] ModifyInstanceAttribute description")
d.SetPartial("description")
args.Description = d.Get("description").(string)
@ -386,7 +435,7 @@ func resourceAliyunInstanceUpdate(d *schema.ResourceData, meta interface{}) erro
attributeUpdate = true
}
if d.HasChange("host_name") {
if d.HasChange("host_name") && !d.IsNewResource() {
log.Printf("[DEBUG] ModifyInstanceAttribute host_name")
d.SetPartial("host_name")
args.HostName = d.Get("host_name").(string)
@ -395,7 +444,7 @@ func resourceAliyunInstanceUpdate(d *schema.ResourceData, meta interface{}) erro
}
passwordUpdate := false
if d.HasChange("password") {
if d.HasChange("password") && !d.IsNewResource() {
log.Printf("[DEBUG] ModifyInstanceAttribute password")
d.SetPartial("password")
args.Password = d.Get("password").(string)
@ -410,18 +459,27 @@ func resourceAliyunInstanceUpdate(d *schema.ResourceData, meta interface{}) erro
}
}
if passwordUpdate {
if v, ok := d.GetOk("status"); ok && v.(string) != "" {
if ecs.InstanceStatus(d.Get("status").(string)) == ecs.Running {
log.Printf("[DEBUG] RebootInstance after change password")
if err := conn.RebootInstance(d.Id(), false); err != nil {
return fmt.Errorf("RebootInstance got error: %#v", err)
}
if err := conn.WaitForInstance(d.Id(), ecs.Running, defaultTimeout); err != nil {
return fmt.Errorf("WaitForInstance got error: %#v", err)
}
if imageUpdate || passwordUpdate {
instance, errDesc := conn.DescribeInstanceAttribute(d.Id())
if errDesc != nil {
return fmt.Errorf("Describe instance got an error: %#v", errDesc)
}
if instance.Status != ecs.Running && instance.Status != ecs.Stopped {
return fmt.Errorf("ECS instance's status doesn't support to start or reboot operation after replace image_id or update password. The current instance's status is %#v", instance.Status)
} else if instance.Status == ecs.Running {
log.Printf("[DEBUG] Reboot instance after change image or password")
if err := conn.RebootInstance(d.Id(), false); err != nil {
return fmt.Errorf("RebootInstance got error: %#v", err)
}
} else {
log.Printf("[DEBUG] Start instance after change image or password")
if err := conn.StartInstance(d.Id()); err != nil {
return fmt.Errorf("StartInstance got error: %#v", err)
}
}
// Start instance sometimes costs more than 6 minutes when os type is centos.
if err := conn.WaitForInstance(d.Id(), ecs.Running, 400); err != nil {
return fmt.Errorf("WaitForInstance got error: %#v", err)
}
}

View File

@ -410,6 +410,39 @@ func TestAccAlicloudInstance_update(t *testing.T) {
})
}
func TestAccAlicloudInstanceImage_update(t *testing.T) {
var instance ecs.InstanceAttributesType
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
CheckDestroy: testAccCheckInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccCheckInstanceImageOrigin,
Check: resource.ComposeTestCheckFunc(
testAccCheckInstanceExists("alicloud_instance.update_image", &instance),
resource.TestCheckResourceAttr(
"alicloud_instance.update_image",
"system_disk_size",
"50"),
),
},
resource.TestStep{
Config: testAccCheckInstanceImageUpdate,
Check: resource.ComposeTestCheckFunc(
testAccCheckInstanceExists("alicloud_instance.update_image", &instance),
resource.TestCheckResourceAttr(
"alicloud_instance.update_image",
"system_disk_size",
"60"),
),
},
},
})
}
func TestAccAlicloudInstance_privateIP(t *testing.T) {
var instance ecs.InstanceAttributesType
@ -1223,5 +1256,78 @@ resource "alicloud_instance" "foo" {
instance_name = "test_foo"
io_optimized = "optimized"
}
`
const testAccCheckInstanceImageOrigin = `
data "alicloud_images" "centos" {
most_recent = true
owners = "system"
name_regex = "^centos_6\\w{1,5}[64]{1}.*"
}
resource "alicloud_vpc" "foo" {
name = "tf_test_image"
cidr_block = "10.1.0.0/21"
}
resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "10.1.1.0/24"
availability_zone = "cn-beijing-a"
}
resource "alicloud_security_group" "tf_test_foo" {
name = "tf_test_foo"
description = "foo"
vpc_id = "${alicloud_vpc.foo.id}"
}
resource "alicloud_instance" "update_image" {
image_id = "${data.alicloud_images.centos.images.0.id}"
availability_zone = "cn-beijing-a"
system_disk_category = "cloud_efficiency"
system_disk_size = 50
instance_type = "ecs.n1.small"
internet_charge_type = "PayByBandwidth"
instance_name = "update_image"
io_optimized = "optimized"
password = "Test12345"
}
`
const testAccCheckInstanceImageUpdate = `
data "alicloud_images" "ubuntu" {
most_recent = true
owners = "system"
name_regex = "^ubuntu_14\\w{1,5}[64]{1}.*"
}
resource "alicloud_vpc" "foo" {
name = "tf_test_image"
cidr_block = "10.1.0.0/21"
}
resource "alicloud_vswitch" "foo" {
vpc_id = "${alicloud_vpc.foo.id}"
cidr_block = "10.1.1.0/24"
availability_zone = "cn-beijing-a"
}
resource "alicloud_security_group" "tf_test_foo" {
name = "tf_test_foo"
description = "foo"
vpc_id = "${alicloud_vpc.foo.id}"
}
resource "alicloud_instance" "update_image" {
image_id = "${data.alicloud_images.ubuntu.images.0.id}"
availability_zone = "cn-beijing-a"
system_disk_category = "cloud_efficiency"
system_disk_size = 60
instance_type = "ecs.n1.small"
internet_charge_type = "PayByBandwidth"
instance_name = "update_image"
io_optimized = "optimized"
password = "Test12345"
}
`

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=ResourceMode -output=resource_mode_string.go resource_mode.go"; DO NOT EDIT.
// Code generated by "stringer -type=ResourceMode -output=resource_mode_string.go resource_mode.go"; DO NOT EDIT
package config

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=getSource resource_data_get_source.go"; DO NOT EDIT.
// Code generated by "stringer -type=getSource resource_data_get_source.go"; DO NOT EDIT
package schema

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=ValueType valuetype.go"; DO NOT EDIT.
// Code generated by "stringer -type=ValueType valuetype.go"; DO NOT EDIT
package schema

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=GraphType context_graph_type.go"; DO NOT EDIT.
// Code generated by "stringer -type=GraphType context_graph_type.go"; DO NOT EDIT
package terraform

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=InstanceType instancetype.go"; DO NOT EDIT.
// Code generated by "stringer -type=InstanceType instancetype.go"; DO NOT EDIT
package terraform

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=walkOperation graph_walk_operation.go"; DO NOT EDIT.
// Code generated by "stringer -type=walkOperation graph_walk_operation.go"; DO NOT EDIT
package terraform

View File

@ -49,3 +49,34 @@ func (client *Client) DescribeInstanceTypesNew(args *DescribeInstanceTypesArgs)
return response.InstanceTypes.InstanceType, nil
}
type DescribeInstanceTypeFamiliesArgs struct {
RegionId common.Region
Generation string
}
type InstanceTypeFamilies struct {
InstanceTypeFamily []InstanceTypeFamily
}
type InstanceTypeFamily struct {
InstanceTypeFamilyId string
Generation string
}
type DescribeInstanceTypeFamiliesResponse struct {
common.Response
InstanceTypeFamilies InstanceTypeFamilies
}
func (client *Client) DescribeInstanceTypeFamilies(args *DescribeInstanceTypeFamiliesArgs) (*DescribeInstanceTypeFamiliesResponse, error) {
response := &DescribeInstanceTypeFamiliesResponse{}
err := client.Invoke("DescribeInstanceTypeFamilies", args, response)
if err != nil {
return nil, err
}
return response, nil
}

View File

@ -336,16 +336,11 @@ func (client *Client) WaitForInstanceAsyn(instanceId string, status InstanceStat
instance, err := client.DescribeInstanceAttribute(instanceId)
if err != nil {
e, _ := err.(*common.Error)
if e.ErrorResponse.Code != "InvalidInstanceId.NotFound" {
if e.Code != "InvalidInstanceId.NotFound" && e.Code != "Forbidden.InstanceNotFound" {
return err
}
time.Sleep(DefaultWaitForInterval * time.Second)
continue
}
if instance.Status == status {
} else if instance != nil && instance.Status == status {
//TODO
//Sleep one more time for timing issues
time.Sleep(DefaultWaitForInterval * time.Second)
break
}
timeout = timeout - DefaultWaitForInterval

View File

@ -0,0 +1,144 @@
package ecs
import (
"github.com/denverdino/aliyungo/common"
)
type CreateKeyPairArgs struct {
RegionId common.Region
KeyPairName string
}
type CreateKeyPairResponse struct {
common.Response
KeyPairName string
KeyPairFingerPrint string
PrivateKeyBody string
}
// CreateKeyPair creates keypair
//
// You can read doc at https://help.aliyun.com/document_detail/51771.html?spm=5176.doc51775.6.910.cedjfr
func (client *Client) CreateKeyPair(args *CreateKeyPairArgs) (resp *CreateKeyPairResponse,err error) {
response := CreateKeyPairResponse{}
err = client.Invoke("CreateKeyPair", args, &response)
if err != nil {
return nil, err
}
return &response, err
}
type ImportKeyPairArgs struct {
RegionId common.Region
PublicKeyBody string
KeyPairName string
}
type ImportKeyPairResponse struct {
common.Response
KeyPairName string
KeyPairFingerPrint string
}
// ImportKeyPair import keypair
//
// You can read doc at https://help.aliyun.com/document_detail/51774.html?spm=5176.doc51771.6.911.BicQq2
func (client *Client) ImportKeyPair(args *ImportKeyPairArgs) (resp *ImportKeyPairResponse,err error) {
response := ImportKeyPairResponse{}
err = client.Invoke("ImportKeyPair", args, &response)
if err != nil {
return nil, err
}
return &response, err
}
type DescribeKeyPairsArgs struct {
RegionId common.Region
KeyPairFingerPrint string
KeyPairName string
common.Pagination
}
type KeyPairItemType struct {
KeyPairName string
KeyPairFingerPrint string
}
type DescribeKeyPairsResponse struct {
common.Response
common.PaginationResult
RegionId common.Region
KeyPairs struct {
KeyPair []KeyPairItemType
}
}
// DescribeKeyPairs describe keypairs
//
// You can read doc at https://help.aliyun.com/document_detail/51773.html?spm=5176.doc51774.6.912.lyE0iX
func (client *Client) DescribeKeyPairs(args *DescribeKeyPairsArgs) (KeyPairs []KeyPairItemType, pagination *common.PaginationResult, err error) {
response := DescribeKeyPairsResponse{}
err = client.Invoke("DescribeKeyPairs", args, &response)
if err != nil {
return nil, nil, err
}
return response.KeyPairs.KeyPair, &response.PaginationResult, err
}
type AttachKeyPairArgs struct {
RegionId common.Region
KeyPairName string
InstanceIds string
}
// AttachKeyPair keypars to instances
//
// You can read doc at https://help.aliyun.com/document_detail/51775.html?spm=5176.doc51773.6.913.igEem4
func (client *Client) AttachKeyPair(args *AttachKeyPairArgs) (err error) {
response := common.Response{}
err = client.Invoke("AttachKeyPair", args, &response)
if err != nil {
return err
}
return nil
}
type DetachKeyPairArgs struct {
RegionId common.Region
KeyPairName string
InstanceIds string
}
// DetachKeyPair keyparis from instances
//
// You can read doc at https://help.aliyun.com/document_detail/51776.html?spm=5176.doc51775.6.914.DJ7Gmq
func (client *Client) DetachKeyPair(args *DetachKeyPairArgs) (err error) {
response := common.Response{}
err = client.Invoke("DetachKeyPair", args, &response)
if err != nil {
return err
}
return nil
}
type DeleteKeyPairsArgs struct {
RegionId common.Region
KeyPairNames string
}
// DeleteKeyPairs delete keypairs
//
// You can read doc at https://help.aliyun.com/document_detail/51772.html?spm=5176.doc51776.6.915.Qqcv2Q
func (client *Client) DeleteKeyPairs(args *DeleteKeyPairsArgs) (err error) {
response := common.Response{}
err = client.Invoke("DeleteKeyPairs", args, &response)
if err != nil {
return err
}
return nil
}

View File

@ -345,6 +345,44 @@ func (client *Client) WaitForInstance(instanceId string, status InstanceStatus,
return nil
}
// WaitForInstance waits for instance to given status
func (client *Client) WaitForInstanceAsyn(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 {
e, _ := err.(*common.Error)
if e.Code != "InvalidInstanceId.NotFound" && e.Code != "Forbidden.InstanceNotFound" {
return err
}
}
if timeout <= 0 {
return common.GetClientErrorFromString("Timeout")
}
timeout = timeout - DefaultWaitForInterval
time.Sleep(DefaultWaitForInterval * time.Second)
if resp != nil {
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

View File

@ -472,6 +472,42 @@ func (client *Client) WaitForListener(loadBalancerId string, port int, listenerT
return response.Status, nil
}
// WaitForListener waits for listener to given status
func (client *Client) WaitForListenerAsyn(loadBalancerId string, port int, listenerType ListenerType, status ListenerStatus, timeout int) error {
if timeout <= 0 {
timeout = DefaultTimeout
}
args := &CommonLoadBalancerListenerArgs{
LoadBalancerId: loadBalancerId,
ListenerPort: port,
}
method := fmt.Sprintf("DescribeLoadBalancer%sListenerAttribute", listenerType)
response := &DescribeLoadBalancerListenerAttributeResponse{}
for {
err := client.Invoke(method, args, response)
e, _ := err.(*common.Error)
if e != nil {
if e.StatusCode == 404 || e.Code == "InvalidLoadBalancerId.NotFound" {
continue
}
return err
} else if response != nil && response.Status == status {
//TODO
break
}
timeout = timeout - DefaultWaitForInterval
if timeout <= 0 {
return common.GetClientErrorFromString("Timeout")
}
time.Sleep(DefaultWaitForInterval * time.Second)
}
return nil
}
type DescribeListenerAccessControlAttributeResponse struct {
common.Response
AccessControlStatus AccessControlStatus

30
vendor/vendor.json vendored
View File

@ -1324,38 +1324,38 @@
{
"checksumSHA1": "4YIveqfMA1MH8oX8YMG7rDSl+ms=",
"path": "github.com/denverdino/aliyungo/common",
"revision": "afcc6903e3f10217da17e315558b3f829718ee04",
"revisionTime": "2017-04-13T09:54:00Z"
"revision": "812f2752cabdc83e7d410c49f25c2b4b99aa166b",
"revisionTime": "2017-05-25T09:14:12Z"
},
{
"checksumSHA1": "WkWWoA5aRYkE2apOEQdAOfn+9cc=",
"checksumSHA1": "x4l/zVF/J4ibAH39pNrSvTnFsPI=",
"path": "github.com/denverdino/aliyungo/ecs",
"revision": "afcc6903e3f10217da17e315558b3f829718ee04",
"revisionTime": "2017-04-13T09:54:00Z"
"revision": "812f2752cabdc83e7d410c49f25c2b4b99aa166b",
"revisionTime": "2017-05-25T09:14:12Z"
},
{
"checksumSHA1": "BgIs8qwCMRM8xL6oLeo2Ki1QwBc=",
"path": "github.com/denverdino/aliyungo/ess",
"revision": "afcc6903e3f10217da17e315558b3f829718ee04",
"revisionTime": "2017-04-13T09:54:00Z"
"revision": "812f2752cabdc83e7d410c49f25c2b4b99aa166b",
"revisionTime": "2017-05-25T09:14:12Z"
},
{
"checksumSHA1": "riQMe2AR7qkLRkQ/MSr8gQp3zL4=",
"checksumSHA1": "XGF+DfnJvqlql64Ygl+eCVxsfVY=",
"path": "github.com/denverdino/aliyungo/rds",
"revision": "afcc6903e3f10217da17e315558b3f829718ee04",
"revisionTime": "2017-04-13T09:54:00Z"
"revision": "812f2752cabdc83e7d410c49f25c2b4b99aa166b",
"revisionTime": "2017-05-25T09:14:12Z"
},
{
"checksumSHA1": "2g6VZONB51rul5YuSBvngH6u4A0=",
"checksumSHA1": "iZftKqx5jdcEaMJNJhrb5QwmMuc=",
"path": "github.com/denverdino/aliyungo/slb",
"revision": "afcc6903e3f10217da17e315558b3f829718ee04",
"revisionTime": "2017-04-13T09:54:00Z"
"revision": "812f2752cabdc83e7d410c49f25c2b4b99aa166b",
"revisionTime": "2017-05-25T09:14:12Z"
},
{
"checksumSHA1": "piZlmhWPLGxYkXLysTrjcXllO4c=",
"path": "github.com/denverdino/aliyungo/util",
"revision": "afcc6903e3f10217da17e315558b3f829718ee04",
"revisionTime": "2017-04-13T09:54:00Z"
"revision": "812f2752cabdc83e7d410c49f25c2b4b99aa166b",
"revisionTime": "2017-05-25T09:14:12Z"
},
{
"checksumSHA1": "yDQQpeUxwqB3C+4opweg6znWJQk=",

View File

@ -54,7 +54,7 @@ resource "alicloud_slb" "vpc" {
The following arguments are supported:
* `image_id` - (Required) The Image to use for the instance.
* `image_id` - (Required) The Image to use for the instance. ECS instance's image can be replaced via changing 'image_id'.
* `instance_type` - (Required) The type of instance to start.
* `io_optimized` - (Required) Valid values are `none`, `optimized`, If `optimized`, the launched ECS instance will be I/O optimized.
* `security_groups` - (Optional) A list of security group ids to associate with.
@ -63,14 +63,14 @@ The following arguments are supported:
Terraform will autogenerate a default name is `ECS-Instance`.
* `allocate_public_ip` - (Optional) Associate a public ip address with an instance in a VPC or Classic. Boolean value, Default is false.
* `system_disk_category` - (Optional) Valid values are `cloud`, `cloud_efficiency`, `cloud_ssd`, For I/O optimized instance type, `cloud_ssd` and `cloud_efficiency` disks are supported. For non I/O Optimized instance type, `cloud` disk are supported.
* `system_disk_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. ECS instance's system disk can be reset when replacing system disk.
* `description` - (Optional) Description of the instance, This description can have a string of 2 to 256 characters, It cannot begin with http:// or https://. Default value is null.
* `internet_charge_type` - (Optional) Internet charge type of the instance, Valid values are `PayByBandwidth`, `PayByTraffic`. Default is `PayByBandwidth`.
* `internet_max_bandwidth_in` - (Optional) Maximum incoming bandwidth from the public network, measured in Mbps (Mega bit per second). Value range: [1, 200]. If this value is not specified, then automatically sets it to 200 Mbps.
* `internet_max_bandwidth_out` - (Optional) Maximum outgoing bandwidth to the public network, measured in Mbps (Mega bit per second). Value range: [0, 100], If this value is not specified, then automatically sets it to 0 Mbps.
* `host_name` - (Optional) Host name of the ECS, which is a string of at least two characters. “hostname” cannot start or end with “.” or “-“. In addition, two or more consecutive “.” or “-“ symbols are not allowed. On Windows, the host name can contain a maximum of 15 characters, which can be a combination of uppercase/lowercase letters, numerals, and “-“. The host name cannot contain dots (“.”) or contain only numeric characters.
On other OSs such as Linux, the host name can contain a maximum of 30 characters, which can be segments separated by dots (“.”), where each segment can contain uppercase/lowercase letters, numerals, or “_“.
* `password` - (Optional) Password to an instance is a string of 8 to 30 characters. It must contain uppercase/lowercase letters and numerals, but cannot contain special symbols.
* `password` - (Optional) Password to an instance is a string of 8 to 30 characters. It must contain uppercase/lowercase letters and numerals, but cannot contain special symbols. In order to take effect new password, the instance will be restarted after modifying the password.
* `vswitch_id` - (Optional) The virtual switch ID to launch in VPC. If you want to create instances in VPC network, this parameter must be set.
* `instance_charge_type` - (Optional) Valid values are `PrePaid`, `PostPaid`, The default is `PostPaid`.
* `period` - (Optional) The time that you have bought the resource, in month. Only valid when instance_charge_type is set as `PrePaid`. Value range [1, 12].