Merge pull request #8250 from tencentyun/master

tencentcloud-cvm builder: we added retry on remote api call to improve the user experience
This commit is contained in:
Megan Marsh 2019-10-21 14:45:37 -07:00 committed by GitHub
commit 0c2fba089d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 2316 additions and 619 deletions

View File

@ -3,6 +3,7 @@
package cvm
import (
"context"
"fmt"
"os"
@ -71,49 +72,67 @@ func (cf *TencentCloudAccessConfig) Client() (*cvm.Client, *vpc.Client, error) {
vpc_client *vpc.Client
resp *cvm.DescribeZonesResponse
)
if err = cf.validateRegion(); err != nil {
return nil, nil, err
}
credential := common.NewCredential(
cf.SecretId, cf.SecretKey)
if cf.Zone == "" {
return nil, nil, fmt.Errorf("parameter zone must be set")
}
credential := common.NewCredential(cf.SecretId, cf.SecretKey)
cpf := profile.NewClientProfile()
cpf.HttpProfile.ReqMethod = "POST"
cpf.HttpProfile.ReqTimeout = 300
cpf.Language = "en-US"
if cvm_client, err = cvm.NewClient(credential, cf.Region, cpf); err != nil {
return nil, nil, err
}
if vpc_client, err = vpc.NewClient(credential, cf.Region, cpf); err != nil {
return nil, nil, err
}
if resp, err = cvm_client.DescribeZones(nil); err != nil {
ctx := context.TODO()
err = Retry(ctx, func(ctx context.Context) error {
var e error
resp, e = cvm_client.DescribeZones(nil)
return e
})
if err != nil {
return nil, nil, err
}
if cf.Zone != "" {
for _, zone := range resp.Response.ZoneSet {
if cf.Zone == *zone.Zone {
return cvm_client, vpc_client, nil
}
for _, zone := range resp.Response.ZoneSet {
if cf.Zone == *zone.Zone {
return cvm_client, vpc_client, nil
}
return nil, nil, fmt.Errorf("unknown zone: %s", cf.Zone)
} else {
return nil, nil, fmt.Errorf("zone must be set")
}
return nil, nil, fmt.Errorf("unknown zone: %s", cf.Zone)
}
func (cf *TencentCloudAccessConfig) Prepare(ctx *interpolate.Context) []error {
var errs []error
if err := cf.Config(); err != nil {
errs = append(errs, err)
}
if cf.Region == "" {
errs = append(errs, fmt.Errorf("region must be set"))
errs = append(errs, fmt.Errorf("parameter region must be set"))
} else if !cf.SkipValidation {
if err := cf.validateRegion(); err != nil {
errs = append(errs, err)
}
}
if len(errs) > 0 {
return errs
}
return nil
}
@ -121,20 +140,28 @@ func (cf *TencentCloudAccessConfig) Config() error {
if cf.SecretId == "" {
cf.SecretId = os.Getenv("TENCENTCLOUD_SECRET_ID")
}
if cf.SecretKey == "" {
cf.SecretKey = os.Getenv("TENCENTCLOUD_SECRET_KEY")
}
if cf.SecretId == "" || cf.SecretKey == "" {
return fmt.Errorf("TENCENTCLOUD_SECRET_ID and TENCENTCLOUD_SECRET_KEY must be set")
return fmt.Errorf("parameter secret_id and secret_key must be set")
}
return nil
}
func (cf *TencentCloudAccessConfig) validateRegion() error {
return validRegion(cf.Region)
}
func validRegion(region string) error {
for _, valid := range ValidRegions {
if valid == Region(cf.Region) {
if Region(region) == valid {
return nil
}
}
return fmt.Errorf("unknown region: %s", cf.Region)
return fmt.Errorf("unknown region: %s", region)
}

View File

@ -1,6 +1,7 @@
package cvm
import (
"context"
"fmt"
"log"
"sort"
@ -29,8 +30,8 @@ func (a *Artifact) Id() string {
for region, imageId := range a.TencentCloudImages {
parts = append(parts, fmt.Sprintf("%s:%s", region, imageId))
}
sort.Strings(parts)
return strings.Join(parts, ",")
}
@ -40,7 +41,8 @@ func (a *Artifact) String() string {
parts = append(parts, fmt.Sprintf("%s: %s", region, imageId))
}
sort.Strings(parts)
return fmt.Sprintf("Tencentcloud images(%s) were created:\n\n", strings.Join(parts, "\n"))
return fmt.Sprintf("Tencentcloud images(%s) were created.\n\n", strings.Join(parts, "\n"))
}
func (a *Artifact) State(name string) interface{} {
@ -53,6 +55,7 @@ func (a *Artifact) State(name string) interface{} {
}
func (a *Artifact) Destroy() error {
ctx := context.TODO()
errors := make([]error, 0)
for region, imageId := range a.TencentCloudImages {
@ -60,22 +63,31 @@ func (a *Artifact) Destroy() error {
describeReq := cvm.NewDescribeImagesRequest()
describeReq.ImageIds = []*string{&imageId}
describeResp, err := a.Client.DescribeImages(describeReq)
var describeResp *cvm.DescribeImagesResponse
err := Retry(ctx, func(ctx context.Context) error {
var e error
describeResp, e = a.Client.DescribeImages(describeReq)
return e
})
if err != nil {
errors = append(errors, err)
continue
}
if *describeResp.Response.TotalCount == 0 {
errors = append(errors, fmt.Errorf(
"describe images failed, region(%s) ImageId(%s)", region, imageId))
}
var shareAccountIds []*string = nil
describeShareReq := cvm.NewDescribeImageSharePermissionRequest()
describeShareReq.ImageId = &imageId
describeShareResp, err := a.Client.DescribeImageSharePermission(describeShareReq)
var shareAccountIds []*string = nil
var describeShareResp *cvm.DescribeImageSharePermissionResponse
err = Retry(ctx, func(ctx context.Context) error {
var e error
describeShareResp, e = a.Client.DescribeImageSharePermission(describeShareReq)
return e
})
if err != nil {
errors = append(errors, err)
} else {
@ -90,7 +102,10 @@ func (a *Artifact) Destroy() error {
cancelShareReq.AccountIds = shareAccountIds
CANCEL := "CANCEL"
cancelShareReq.Permission = &CANCEL
_, err := a.Client.ModifyImageSharePermission(cancelShareReq)
err := Retry(ctx, func(ctx context.Context) error {
_, e := a.Client.ModifyImageSharePermission(cancelShareReq)
return e
})
if err != nil {
errors = append(errors, err)
}
@ -98,8 +113,10 @@ func (a *Artifact) Destroy() error {
deleteReq := cvm.NewDeleteImagesRequest()
deleteReq.ImageIds = []*string{&imageId}
_, err = a.Client.DeleteImages(deleteReq)
err = Retry(ctx, func(ctx context.Context) error {
_, e := a.Client.DeleteImages(deleteReq)
return e
})
if err != nil {
errors = append(errors, err)
}
@ -120,5 +137,6 @@ func (a *Artifact) stateAtlasMetadata() interface{} {
k := fmt.Sprintf("region.%s", region)
metadata[k] = imageId
}
return metadata
}

View File

@ -49,13 +49,13 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs = packer.MultiErrorAppend(errs, b.config.TencentCloudAccessConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.TencentCloudImageConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.TencentCloudRunConfig.Prepare(&b.config.ctx)...)
if errs != nil && len(errs.Errors) > 0 {
return nil, errs
}
packer.LogSecretFilter.Set(b.config.SecretId, b.config.SecretKey)
log.Println(b.config)
log.Printf("[DEBUG]packer config: %v", b.config)
return nil, nil
}
@ -64,17 +64,21 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
if err != nil {
return nil, err
}
state := new(multistep.BasicStateBag)
state.Put("config", &b.config)
state.Put("cvm_client", cvmClient)
state.Put("vpc_client", vpcClient)
state.Put("hook", hook)
state.Put("ui", ui)
var steps []multistep.Step
// Build the steps
var steps []multistep.Step
steps = []multistep.Step{
&stepCheckSourceImage{b.config.SourceImageId},
&stepPreValidate{},
&stepCheckSourceImage{
b.config.SourceImageId,
},
&stepConfigKeyPair{
Debug: b.config.PackerDebug,
Comm: &b.config.Comm,
@ -94,7 +98,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
&stepConfigSecurityGroup{
SecurityGroupId: b.config.SecurityGroupId,
SecurityGroupName: b.config.SecurityGroupName,
Description: "a simple security group",
Description: "securitygroup for packer",
},
&stepRunInstance{
InstanceType: b.config.InstanceType,
@ -119,7 +123,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
&common.StepCleanupTempKeys{
Comm: &b.config.TencentCloudRunConfig.Comm,
},
// We need this step to detach temporary key from instance, otherwise
// We need this step to detach keypair from instance, otherwise
// it always fails to delete the key.
&stepDetachTempKeyPair{},
&stepCreateImage{},
@ -148,5 +152,6 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
BuilderIdValue: BuilderId,
Client: cvmClient,
}
return artifact, nil
}

View File

@ -1,44 +1,35 @@
package cvm
import (
"context"
"fmt"
"regexp"
"strings"
"time"
"github.com/hashicorp/packer/common/retry"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)
func CheckResourceIdFormat(resource string, id string) bool {
regex := regexp.MustCompile(fmt.Sprintf("%s-[0-9a-z]{8}$", resource))
if !regex.MatchString(id) {
return false
}
return true
}
func MessageClean(state multistep.StateBag, module string) {
_, cancelled := state.GetOk(multistep.StateCancelled)
_, halted := state.GetOk(multistep.StateHalted)
ui := state.Get("ui").(packer.Ui)
if cancelled || halted {
ui.Say(fmt.Sprintf("Deleting %s because of cancellation or error...", module))
} else {
ui.Say(fmt.Sprintf("Cleaning up '%s'", module))
}
}
// DefaultWaitForInterval is sleep interval when wait statue
const DefaultWaitForInterval = 5
// WaitForInstance wait for instance reaches statue
func WaitForInstance(client *cvm.Client, instanceId string, status string, timeout int) error {
ctx := context.TODO()
req := cvm.NewDescribeInstancesRequest()
req.InstanceIds = []*string{&instanceId}
for {
resp, err := client.DescribeInstances(req)
var resp *cvm.DescribeInstancesResponse
err := Retry(ctx, func(ctx context.Context) error {
var e error
resp, e = client.DescribeInstances(req)
return e
})
if err != nil {
return err
}
@ -54,10 +45,13 @@ func WaitForInstance(client *cvm.Client, instanceId string, status string, timeo
return fmt.Errorf("wait instance(%s) status(%s) timeout", instanceId, status)
}
}
return nil
}
// WaitForImageReady wait for image reaches statue
func WaitForImageReady(client *cvm.Client, imageName string, status string, timeout int) error {
ctx := context.TODO()
req := cvm.NewDescribeImagesRequest()
FILTER_IMAGE_NAME := "image-name"
req.Filters = []*cvm.Filter{
@ -66,8 +60,14 @@ func WaitForImageReady(client *cvm.Client, imageName string, status string, time
Values: []*string{&imageName},
},
}
for {
resp, err := client.DescribeImages(req)
var resp *cvm.DescribeImagesResponse
err := Retry(ctx, func(ctx context.Context) error {
var e error
resp, e = client.DescribeImages(req)
return e
})
if err != nil {
return err
}
@ -84,12 +84,22 @@ func WaitForImageReady(client *cvm.Client, imageName string, status string, time
time.Sleep(DefaultWaitForInterval * time.Second)
timeout = timeout - DefaultWaitForInterval
if timeout <= 0 {
return fmt.Errorf("wait image(%s) ready timeout", imageName)
return fmt.Errorf("wait image(%s) status(%s) timeout", imageName, status)
}
}
return nil
}
// CheckResourceIdFormat check resource id format
func CheckResourceIdFormat(resource string, id string) bool {
regex := regexp.MustCompile(fmt.Sprintf("%s-[0-9a-z]{8}$", resource))
if !regex.MatchString(id) {
return false
}
return true
}
// SSHHost returns a function that can be given to the SSH communicator
func SSHHost(pubilcIp bool) func(multistep.StateBag) (string, error) {
return func(state multistep.StateBag) (string, error) {
@ -101,3 +111,83 @@ func SSHHost(pubilcIp bool) func(multistep.StateBag) (string, error) {
}
}
}
// Retry do retry on api request
func Retry(ctx context.Context, fn func(context.Context) error) error {
return retry.Config{
Tries: 30,
ShouldRetry: func(err error) bool {
e, ok := err.(*errors.TencentCloudSDKError)
if !ok {
return false
}
if e.Code == "ClientError.NetworkError" || e.Code == "ClientError.HttpStatusCodeError" ||
e.Code == "InvalidKeyPair.NotSupported" || e.Code == "InvalidInstance.NotSupported" ||
strings.Contains(e.Code, "RequestLimitExceeded") || strings.Contains(e.Code, "InternalError") ||
strings.Contains(e.Code, "ResourceInUse") || strings.Contains(e.Code, "ResourceBusy") {
return true
}
return false
},
RetryDelay: (&retry.Backoff{
InitialBackoff: 1 * time.Second,
MaxBackoff: 5 * time.Second,
Multiplier: 2,
}).Linear,
}.Run(ctx, fn)
}
// SayClean tell you clean module message
func SayClean(state multistep.StateBag, module string) {
_, halted := state.GetOk(multistep.StateHalted)
_, cancelled := state.GetOk(multistep.StateCancelled)
if halted {
Say(state, fmt.Sprintf("Deleting %s because of error...", module), "")
} else if cancelled {
Say(state, fmt.Sprintf("Deleting %s because of cancellation...", module), "")
} else {
Say(state, fmt.Sprintf("Cleaning up %s...", module), "")
}
}
// Say tell you a message
func Say(state multistep.StateBag, message, prefix string) {
if prefix != "" {
message = fmt.Sprintf("%s: %s", prefix, message)
}
if strings.HasPrefix(message, "Trying to") {
message += "..."
}
ui := state.Get("ui").(packer.Ui)
ui.Say(message)
}
// Message print a message
func Message(state multistep.StateBag, message, prefix string) {
if prefix != "" {
message = fmt.Sprintf("%s: %s", prefix, message)
}
ui := state.Get("ui").(packer.Ui)
ui.Message(message)
}
// Error print error message
func Error(state multistep.StateBag, err error, prefix string) {
if prefix != "" {
err = fmt.Errorf("%s: %s", prefix, err)
}
ui := state.Get("ui").(packer.Ui)
ui.Error(err.Error())
}
// Halt print error message and exit
func Halt(state multistep.StateBag, err error, prefix string) multistep.StepAction {
Error(state, err, prefix)
state.Put("error", err)
return multistep.ActionHalt
}

View File

@ -36,6 +36,7 @@ type TencentCloudImageConfig struct {
func (cf *TencentCloudImageConfig) Prepare(ctx *interpolate.Context) []error {
var errs []error
cf.ForcePoweroff = true
if cf.ImageName == "" {
errs = append(errs, fmt.Errorf("image_name must be specified"))
@ -68,17 +69,10 @@ func (cf *TencentCloudImageConfig) Prepare(ctx *interpolate.Context) []error {
}
cf.ImageCopyRegions = regions
}
if len(errs) > 0 {
return errs
}
return nil
}
func validRegion(region string) error {
for _, valid := range ValidRegions {
if Region(region) == valid {
return nil
}
}
return fmt.Errorf("unknown region: %s", region)
}

View File

@ -31,5 +31,4 @@ func TestTencentCloudImageConfig_Prepare(t *testing.T) {
if err := cf.Prepare(nil); err != nil {
t.Fatalf("shouldn't have err:%v", err)
}
}

View File

@ -5,6 +5,7 @@ package cvm
import (
"fmt"
"os"
"strings"
"github.com/hashicorp/packer/common/uuid"
"github.com/hashicorp/packer/helper/communicator"
@ -68,7 +69,7 @@ type TencentCloudRunConfig struct {
// Max bandwidth out your cvm will be launched by(in MB).
// values can be set between 1 ~ 100.
InternetMaxBandwidthOut int64 `mapstructure:"internet_max_bandwidth_out" required:"false"`
// Specify security group your cvm will be launched by.
// Specify securitygroup your cvm will be launched by.
SecurityGroupId string `mapstructure:"security_group_id" required:"false"`
// Specify security name you will create if security_group_id not set.
SecurityGroupName string `mapstructure:"security_group_name" required:"false"`
@ -92,10 +93,11 @@ var ValidCBSType = []string{
}
func (cf *TencentCloudRunConfig) Prepare(ctx *interpolate.Context) []error {
packerId := fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID()[:8])
if cf.Comm.SSHKeyPairName == "" && cf.Comm.SSHTemporaryKeyPairName == "" &&
cf.Comm.SSHPrivateKeyFile == "" && cf.Comm.SSHPassword == "" && cf.Comm.WinRMPassword == "" {
//tencentcloud support key pair name length max to 25
cf.Comm.SSHTemporaryKeyPairName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID()[:8])
cf.Comm.SSHTemporaryKeyPairName = packerId
}
errs := cf.Comm.Prepare(ctx)
@ -126,7 +128,7 @@ func (cf *TencentCloudRunConfig) Prepare(ctx *interpolate.Context) []error {
if cf.VpcId == "" {
if cf.VpcName == "" {
cf.VpcName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID())
cf.VpcName = packerId
}
if cf.CidrBlock == "" {
cf.CidrBlock = "10.0.0.0/16"
@ -135,9 +137,10 @@ func (cf *TencentCloudRunConfig) Prepare(ctx *interpolate.Context) []error {
errs = append(errs, errors.New("can't set subnet_id without set vpc_id"))
}
}
if cf.SubnetId == "" {
if cf.SubnetName == "" {
cf.SubnetName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID())
cf.SubnetName = packerId
}
if cf.SubnectCidrBlock == "" {
cf.SubnectCidrBlock = "10.0.8.0/24"
@ -145,7 +148,7 @@ func (cf *TencentCloudRunConfig) Prepare(ctx *interpolate.Context) []error {
}
if cf.SecurityGroupId == "" && cf.SecurityGroupName == "" {
cf.SecurityGroupName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID())
cf.SecurityGroupName = packerId
}
if cf.DiskType != "" && !checkDiskType(cf.DiskType) {
@ -163,13 +166,18 @@ func (cf *TencentCloudRunConfig) Prepare(ctx *interpolate.Context) []error {
}
if cf.InstanceName == "" {
cf.InstanceName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
cf.InstanceName = packerId
}
if cf.HostName == "" {
cf.HostName = cf.InstanceName[:15]
cf.HostName = cf.InstanceName
}
if len(cf.HostName) > 15 {
cf.HostName = cf.HostName[:15]
}
cf.HostName = strings.Replace(cf.HostName, "_", "-", -1)
if cf.RunTags == nil {
cf.RunTags = make(map[string]string)
}
@ -183,5 +191,6 @@ func checkDiskType(diskType string) bool {
return true
}
}
return false
}

View File

@ -60,6 +60,7 @@ func TestTencentCloudRunConfig_Prepare(t *testing.T) {
func TestTencentCloudRunConfigPrepare_UserData(t *testing.T) {
cf := testConfig()
tf, err := ioutil.TempFile("", "packer")
if err != nil {
t.Fatalf("new temp file failed: %v", err)
@ -76,6 +77,7 @@ func TestTencentCloudRunConfigPrepare_UserData(t *testing.T) {
func TestTencentCloudRunConfigPrepare_UserDataFile(t *testing.T) {
cf := testConfig()
cf.UserDataFile = "not-exist-file"
if err := cf.Prepare(nil); err == nil {
t.Fatal("should have error")
@ -117,13 +119,16 @@ func TestTencentCloudRunConfigPrepare_TemporaryKeyPairName(t *testing.T) {
func TestTencentCloudRunConfigPrepare_SSHPrivateIp(t *testing.T) {
cf := testConfig()
if cf.SSHPrivateIp != false {
t.Fatalf("invalid ssh_private_ip value: %v", cf.SSHPrivateIp)
}
cf.SSHPrivateIp = true
if err := cf.Prepare(nil); err != nil {
t.Fatalf("shouldn't have error: %v", err)
}
if cf.SSHPrivateIp != true {
t.Fatalf("invalud ssh_private_ip value: %v", cf.SSHPrivateIp)
}

View File

@ -5,7 +5,6 @@ import (
"fmt"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)
@ -14,32 +13,31 @@ type stepCheckSourceImage struct {
}
func (s *stepCheckSourceImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("cvm_client").(*cvm.Client)
config := state.Get("config").(*Config)
ui := state.Get("ui").(packer.Ui)
client := state.Get("cvm_client").(*cvm.Client)
Say(state, config.SourceImageId, "Trying to check source image")
req := cvm.NewDescribeImagesRequest()
req.ImageIds = []*string{&config.SourceImageId}
req.InstanceType = &config.InstanceType
resp, err := client.DescribeImages(req)
var resp *cvm.DescribeImagesResponse
err := Retry(ctx, func(ctx context.Context) error {
var err error
resp, err = client.DescribeImages(req)
return err
})
if err != nil {
err := fmt.Errorf("querying image info failed: %s", err.Error())
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
return Halt(state, err, "Failed to get source image info")
}
if *resp.Response.TotalCount > 0 { // public image or private image.
if *resp.Response.TotalCount > 0 {
state.Put("source_image", resp.Response.ImageSet[0])
ui.Message(fmt.Sprintf("Image found: %s", *resp.Response.ImageSet[0].ImageId))
Message(state, *resp.Response.ImageSet[0].ImageName, "Image found")
return multistep.ActionContinue
}
// later market image will be included.
err = fmt.Errorf("no image founded under current instance_type(%s) restriction", config.InstanceType)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
return Halt(state, fmt.Errorf("No image found under current instance_type(%s) restriction", config.InstanceType), "")
}
func (s *stepCheckSourceImage) Cleanup(bag multistep.StateBag) {}

View File

@ -6,12 +6,9 @@ import (
"io/ioutil"
"os"
"runtime"
"time"
"github.com/hashicorp/packer/common/retry"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)
@ -19,83 +16,79 @@ type stepConfigKeyPair struct {
Debug bool
Comm *communicator.Config
DebugKeyPath string
keyID string
keyID string
}
func (s *stepConfigKeyPair) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
client := state.Get("cvm_client").(*cvm.Client)
if s.Comm.SSHPrivateKeyFile != "" {
ui.Say("Using existing SSH private key")
Say(state, "Using existing SSH private key", "")
privateKeyBytes, err := ioutil.ReadFile(s.Comm.SSHPrivateKeyFile)
if err != nil {
state.Put("error", fmt.Errorf(
"loading configured private key file failed: %s", err))
return multistep.ActionHalt
return Halt(state, err, fmt.Sprintf("Failed to load configured private key(%s)", s.Comm.SSHPrivateKeyFile))
}
s.Comm.SSHPrivateKey = privateKeyBytes
Message(state, fmt.Sprintf("Loaded %d bytes private key data", len(s.Comm.SSHPrivateKey)), "")
return multistep.ActionContinue
}
if s.Comm.SSHAgentAuth && s.Comm.SSHKeyPairName == "" {
ui.Say("Using SSH Agent with key pair in source image")
return multistep.ActionContinue
}
if s.Comm.SSHAgentAuth && s.Comm.SSHKeyPairName != "" {
ui.Say(fmt.Sprintf("Using SSH Agent for existing key pair %s", s.Comm.SSHKeyPairName))
if s.Comm.SSHAgentAuth {
if s.Comm.SSHKeyPairName == "" {
Say(state, "Using SSH agent with key pair in source image", "")
return multistep.ActionContinue
}
Say(state, fmt.Sprintf("Using SSH agent with exists key pair(%s)", s.Comm.SSHKeyPairName), "")
return multistep.ActionContinue
}
if s.Comm.SSHTemporaryKeyPairName == "" {
ui.Say("Not using temporary keypair")
Say(state, "Not to use temporary keypair", "")
s.Comm.SSHKeyPairName = ""
return multistep.ActionContinue
}
client := state.Get("cvm_client").(*cvm.Client)
ui.Say(fmt.Sprintf("Creating temporary keypair: %s", s.Comm.SSHTemporaryKeyPairName))
Say(state, s.Comm.SSHTemporaryKeyPairName, "Trying to create a new keypair")
req := cvm.NewCreateKeyPairRequest()
req.KeyName = &s.Comm.SSHTemporaryKeyPairName
defaultProjectId := int64(0)
req.ProjectId = &defaultProjectId
resp, err := client.CreateKeyPair(req)
var resp *cvm.CreateKeyPairResponse
err := Retry(ctx, func(ctx context.Context) error {
var e error
resp, e = client.CreateKeyPair(req)
return e
})
if err != nil {
state.Put("error", fmt.Errorf("creating temporary keypair failed: %s", err.Error()))
return multistep.ActionHalt
return Halt(state, err, "Failed to create keypair")
}
// set keyId to delete when Cleanup
s.keyID = *resp.Response.KeyPair.KeyId
state.Put("temporary_key_pair_id", resp.Response.KeyPair.KeyId)
state.Put("temporary_key_pair_id", s.keyID)
Message(state, s.keyID, "Keypair created")
s.Comm.SSHKeyPairName = *resp.Response.KeyPair.KeyId
s.Comm.SSHPrivateKey = []byte(*resp.Response.KeyPair.PrivateKey)
if s.Debug {
ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath))
Message(state, fmt.Sprintf("Saving temporary key to %s for debug purposes", s.DebugKeyPath), "")
f, err := os.Create(s.DebugKeyPath)
if err != nil {
state.Put("error", fmt.Errorf("creating debug key file failed:%s", err.Error()))
return multistep.ActionHalt
return Halt(state, err, "Failed to saving debug key file")
}
defer f.Close()
if _, err := f.Write([]byte(*resp.Response.KeyPair.PrivateKey)); err != nil {
state.Put("error", fmt.Errorf("writing debug key file failed:%s", err.Error()))
return multistep.ActionHalt
return Halt(state, err, "Failed to writing debug key file")
}
if runtime.GOOS != "windows" {
if err := f.Chmod(0600); err != nil {
state.Put("error", fmt.Errorf("setting debug key file's permission failed:%s", err.Error()))
return multistep.ActionHalt
return Halt(state, err, "Failed to chmod debug key file")
}
}
}
return multistep.ActionContinue
}
@ -103,28 +96,25 @@ func (s *stepConfigKeyPair) Cleanup(state multistep.StateBag) {
if s.Comm.SSHPrivateKeyFile != "" || (s.Comm.SSHKeyPairName == "" && s.keyID == "") {
return
}
ctx := context.TODO()
client := state.Get("cvm_client").(*cvm.Client)
ui := state.Get("ui").(packer.Ui)
ui.Say("Deleting temporary keypair...")
SayClean(state, "keypair")
req := cvm.NewDeleteKeyPairsRequest()
req.KeyIds = []*string{&s.keyID}
err := retry.Config{
Tries: 60,
RetryDelay: (&retry.Backoff{InitialBackoff: 5 * time.Second, MaxBackoff: 5 * time.Second, Multiplier: 2}).Linear,
}.Run(ctx, func(ctx context.Context) error {
_, err := client.DeleteKeyPairs(req)
return err
err := Retry(ctx, func(ctx context.Context) error {
_, e := client.DeleteKeyPairs(req)
return e
})
if err != nil {
ui.Error(fmt.Sprintf(
"delete keypair failed, please delete it manually, keyId: %s, err: %s", s.keyID, err.Error()))
Error(state, err, fmt.Sprintf("Failed to delete keypair(%s), please delete it manually", s.keyID))
}
if s.Debug {
if err := os.Remove(s.DebugKeyPath); err != nil {
ui.Error(fmt.Sprintf("delete debug key file %s failed: %s", s.DebugKeyPath, err.Error()))
Error(state, err, fmt.Sprintf("Failed to delete debug key file(%s), please delete it manually", s.DebugKeyPath))
}
}
}

View File

@ -2,14 +2,9 @@ package cvm
import (
"context"
"time"
"fmt"
"github.com/hashicorp/packer/common/retry"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/pkg/errors"
vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312"
)
@ -22,42 +17,51 @@ type stepConfigSecurityGroup struct {
func (s *stepConfigSecurityGroup) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
vpcClient := state.Get("vpc_client").(*vpc.Client)
ui := state.Get("ui").(packer.Ui)
if len(s.SecurityGroupId) != 0 { // use existing security group
if len(s.SecurityGroupId) != 0 {
Say(state, s.SecurityGroupId, "Trying to use existing securitygroup")
req := vpc.NewDescribeSecurityGroupsRequest()
req.SecurityGroupIds = []*string{&s.SecurityGroupId}
resp, err := vpcClient.DescribeSecurityGroups(req)
var resp *vpc.DescribeSecurityGroupsResponse
err := Retry(ctx, func(ctx context.Context) error {
var e error
resp, e = vpcClient.DescribeSecurityGroups(req)
return e
})
if err != nil {
ui.Error(fmt.Sprintf("query security group failed: %s", err.Error()))
state.Put("error", err)
return multistep.ActionHalt
return Halt(state, err, "Failed to get securitygroup info")
}
if *resp.Response.TotalCount > 0 {
state.Put("security_group_id", s.SecurityGroupId)
s.isCreate = false
state.Put("security_group_id", s.SecurityGroupId)
Message(state, *resp.Response.SecurityGroupSet[0].SecurityGroupName, "Securitygroup found")
return multistep.ActionContinue
}
message := fmt.Sprintf("the specified security group(%s) does not exist", s.SecurityGroupId)
ui.Error(message)
state.Put("error", errors.New(message))
return multistep.ActionHalt
return Halt(state, fmt.Errorf("The specified securitygroup(%s) does not exists", s.SecurityGroupId), "")
}
// create a new security group
Say(state, "Trying to create a new securitygroup", "")
req := vpc.NewCreateSecurityGroupRequest()
req.GroupName = &s.SecurityGroupName
req.GroupDescription = &s.Description
resp, err := vpcClient.CreateSecurityGroup(req)
var resp *vpc.CreateSecurityGroupResponse
err := Retry(ctx, func(ctx context.Context) error {
var e error
resp, e = vpcClient.CreateSecurityGroup(req)
return e
})
if err != nil {
ui.Error(fmt.Sprintf("create security group failed: %s", err.Error()))
state.Put("error", err)
return multistep.ActionHalt
return Halt(state, err, "Failed to create securitygroup")
}
s.isCreate = true
s.SecurityGroupId = *resp.Response.SecurityGroup.SecurityGroupId
state.Put("security_group_id", s.SecurityGroupId)
s.isCreate = true
Message(state, s.SecurityGroupId, "Securitygroup created")
// bind security group ingress police
// bind securitygroup ingress police
Say(state, "Trying to create securitygroup polices", "")
pReq := vpc.NewCreateSecurityGroupPoliciesRequest()
ACCEPT := "ACCEPT"
DEFAULT_CIDR := "0.0.0.0/0"
@ -70,14 +74,15 @@ func (s *stepConfigSecurityGroup) Run(ctx context.Context, state multistep.State
},
},
}
_, err = vpcClient.CreateSecurityGroupPolicies(pReq)
err = Retry(ctx, func(ctx context.Context) error {
_, e := vpcClient.CreateSecurityGroupPolicies(pReq)
return e
})
if err != nil {
ui.Error(fmt.Sprintf("bind security group police failed: %s", err.Error()))
state.Put("error", err)
return multistep.ActionHalt
return Halt(state, err, "Failed to create securitygroup polices")
}
// bind security group engress police
// bind securitygroup engress police
pReq = vpc.NewCreateSecurityGroupPoliciesRequest()
pReq.SecurityGroupId = &s.SecurityGroupId
pReq.SecurityGroupPolicySet = &vpc.SecurityGroupPolicySet{
@ -88,13 +93,16 @@ func (s *stepConfigSecurityGroup) Run(ctx context.Context, state multistep.State
},
},
}
_, err = vpcClient.CreateSecurityGroupPolicies(pReq)
err = Retry(ctx, func(ctx context.Context) error {
_, e := vpcClient.CreateSecurityGroupPolicies(pReq)
return e
})
if err != nil {
ui.Error(fmt.Sprintf("bind security group police failed: %s", err.Error()))
state.Put("error", err)
return multistep.ActionHalt
return Halt(state, err, "Failed to create securitygroup polices")
}
Message(state, "Securitygroup polices created", "")
return multistep.ActionContinue
}
@ -102,23 +110,19 @@ func (s *stepConfigSecurityGroup) Cleanup(state multistep.StateBag) {
if !s.isCreate {
return
}
ctx := context.TODO()
vpcClient := state.Get("vpc_client").(*vpc.Client)
ui := state.Get("ui").(packer.Ui)
MessageClean(state, "Security Group")
SayClean(state, "securitygroup")
req := vpc.NewDeleteSecurityGroupRequest()
req.SecurityGroupId = &s.SecurityGroupId
err := retry.Config{
Tries: 60,
RetryDelay: (&retry.Backoff{InitialBackoff: 5 * time.Second, MaxBackoff: 5 * time.Second, Multiplier: 2}).Linear,
}.Run(ctx, func(ctx context.Context) error {
_, err := vpcClient.DeleteSecurityGroup(req)
return err
err := Retry(ctx, func(ctx context.Context) error {
_, e := vpcClient.DeleteSecurityGroup(req)
return e
})
if err != nil {
ui.Error(fmt.Sprintf("delete security group(%s) failed: %s, you need to delete it by hand",
s.SecurityGroupId, err.Error()))
return
Error(state, err, fmt.Sprintf("Failed to delete securitygroup(%s), please delete it manually", s.SecurityGroupId))
}
}

View File

@ -3,12 +3,8 @@ package cvm
import (
"context"
"fmt"
"time"
"github.com/hashicorp/packer/common/retry"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/pkg/errors"
vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312"
)
@ -22,79 +18,76 @@ type stepConfigSubnet struct {
func (s *stepConfigSubnet) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
vpcClient := state.Get("vpc_client").(*vpc.Client)
ui := state.Get("ui").(packer.Ui)
vpcId := state.Get("vpc_id").(string)
if len(s.SubnetId) != 0 { // exist subnet
ui.Say(fmt.Sprintf("Trying to use existing subnet(%s)", s.SubnetId))
if len(s.SubnetId) != 0 {
Say(state, s.SubnetId, "Trying to use existing subnet")
req := vpc.NewDescribeSubnetsRequest()
req.SubnetIds = []*string{&s.SubnetId}
resp, err := vpcClient.DescribeSubnets(req)
var resp *vpc.DescribeSubnetsResponse
err := Retry(ctx, func(ctx context.Context) error {
var e error
resp, e = vpcClient.DescribeSubnets(req)
return e
})
if err != nil {
ui.Error(fmt.Sprintf("query subnet failed: %s", err.Error()))
state.Put("error", err)
return multistep.ActionHalt
return Halt(state, err, "Failed to get subnet info")
}
if *resp.Response.TotalCount > 0 {
subnet0 := *resp.Response.SubnetSet[0]
if *subnet0.VpcId != vpcId {
message := fmt.Sprintf("the specified subnet(%s) does not belong to "+
"the specified vpc(%s)", s.SubnetId, vpcId)
ui.Error(message)
state.Put("error", errors.New(message))
return multistep.ActionHalt
}
state.Put("subnet_id", *subnet0.SubnetId)
s.isCreate = false
if *resp.Response.SubnetSet[0].VpcId != vpcId {
return Halt(state, fmt.Errorf("The specified subnet(%s) does not belong to the specified vpc(%s)", s.SubnetId, vpcId), "")
}
state.Put("subnet_id", *resp.Response.SubnetSet[0].SubnetId)
Message(state, *resp.Response.SubnetSet[0].SubnetName, "Subnet found")
return multistep.ActionContinue
}
message := fmt.Sprintf("the specified subnet(%s) does not exist", s.SubnetId)
state.Put("error", errors.New(message))
ui.Error(message)
return multistep.ActionHalt
} else { // create a new subnet, tencentcloud create subnet api is synchronous, no need to wait for create.
ui.Say(fmt.Sprintf("Trying to create a new subnet"))
req := vpc.NewCreateSubnetRequest()
req.VpcId = &vpcId
req.SubnetName = &s.SubnetName
req.CidrBlock = &s.SubnetCidrBlock
req.Zone = &s.Zone
resp, err := vpcClient.CreateSubnet(req)
if err != nil {
ui.Error(fmt.Sprintf("create subnet failed: %s", err.Error()))
state.Put("error", err)
return multistep.ActionHalt
}
subnet0 := *resp.Response.Subnet
state.Put("subnet_id", *subnet0.SubnetId)
s.SubnetId = *subnet0.SubnetId
s.isCreate = true
return multistep.ActionContinue
return Halt(state, fmt.Errorf("The specified subnet(%s) does not exist", s.SubnetId), "")
}
Say(state, "Trying to create a new subnet", "")
req := vpc.NewCreateSubnetRequest()
req.VpcId = &vpcId
req.SubnetName = &s.SubnetName
req.CidrBlock = &s.SubnetCidrBlock
req.Zone = &s.Zone
var resp *vpc.CreateSubnetResponse
err := Retry(ctx, func(ctx context.Context) error {
var e error
resp, e = vpcClient.CreateSubnet(req)
return e
})
if err != nil {
return Halt(state, err, "Failed to create subnet")
}
s.isCreate = true
s.SubnetId = *resp.Response.Subnet.SubnetId
state.Put("subnet_id", s.SubnetId)
Message(state, s.SubnetId, "Subnet created")
return multistep.ActionContinue
}
func (s *stepConfigSubnet) Cleanup(state multistep.StateBag) {
if !s.isCreate {
return
}
ctx := context.TODO()
vpcClient := state.Get("vpc_client").(*vpc.Client)
ui := state.Get("ui").(packer.Ui)
MessageClean(state, "SUBNET")
SayClean(state, "subnet")
req := vpc.NewDeleteSubnetRequest()
req.SubnetId = &s.SubnetId
err := retry.Config{
Tries: 60,
RetryDelay: (&retry.Backoff{InitialBackoff: 5 * time.Second, MaxBackoff: 5 * time.Second, Multiplier: 2}).Linear,
}.Run(ctx, func(ctx context.Context) error {
_, err := vpcClient.DeleteSubnet(req)
return err
err := Retry(ctx, func(ctx context.Context) error {
_, e := vpcClient.DeleteSubnet(req)
return e
})
if err != nil {
ui.Error(fmt.Sprintf("delete subnet(%s) failed: %s, you need to delete it by hand",
s.SubnetId, err.Error()))
return
Error(state, err, fmt.Sprintf("Failed to delete subnet(%s), please delete it manually", s.SubnetId))
}
}

View File

@ -3,12 +3,8 @@ package cvm
import (
"context"
"fmt"
"time"
"github.com/hashicorp/packer/common/retry"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/pkg/errors"
vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312"
)
@ -21,69 +17,69 @@ type stepConfigVPC struct {
func (s *stepConfigVPC) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
vpcClient := state.Get("vpc_client").(*vpc.Client)
ui := state.Get("ui").(packer.Ui)
if len(s.VpcId) != 0 { // exist vpc
ui.Say(fmt.Sprintf("Trying to use existing vpc(%s)", s.VpcId))
if len(s.VpcId) != 0 {
Say(state, s.VpcId, "Trying to use existing vpc")
req := vpc.NewDescribeVpcsRequest()
req.VpcIds = []*string{&s.VpcId}
resp, err := vpcClient.DescribeVpcs(req)
var resp *vpc.DescribeVpcsResponse
err := Retry(ctx, func(ctx context.Context) error {
var e error
resp, e = vpcClient.DescribeVpcs(req)
return e
})
if err != nil {
ui.Error(fmt.Sprintf("query vpc failed: %s", err.Error()))
state.Put("error", err)
return multistep.ActionHalt
return Halt(state, err, "Failed to get vpc info")
}
if *resp.Response.TotalCount > 0 {
vpc0 := *resp.Response.VpcSet[0]
state.Put("vpc_id", *vpc0.VpcId)
s.isCreate = false
state.Put("vpc_id", *resp.Response.VpcSet[0].VpcId)
Message(state, *resp.Response.VpcSet[0].VpcName, "Vpc found")
return multistep.ActionContinue
}
message := fmt.Sprintf("the specified vpc(%s) does not exist", s.VpcId)
state.Put("error", errors.New(message))
ui.Error(message)
return multistep.ActionHalt
} else { // create a new vpc, tencentcloud create vpc api is synchronous, no need to wait for create.
ui.Say(fmt.Sprintf("Trying to create a new vpc"))
req := vpc.NewCreateVpcRequest()
req.VpcName = &s.VpcName
req.CidrBlock = &s.CidrBlock
resp, err := vpcClient.CreateVpc(req)
if err != nil {
ui.Error(fmt.Sprintf("create vpc failed: %s", err.Error()))
state.Put("error", err)
return multistep.ActionHalt
}
vpc0 := *resp.Response.Vpc
state.Put("vpc_id", *vpc0.VpcId)
s.VpcId = *vpc0.VpcId
s.isCreate = true
return multistep.ActionContinue
return Halt(state, fmt.Errorf("The specified vpc(%s) does not exist", s.VpcId), "")
}
Say(state, "Trying to create a new vpc", "")
req := vpc.NewCreateVpcRequest()
req.VpcName = &s.VpcName
req.CidrBlock = &s.CidrBlock
var resp *vpc.CreateVpcResponse
err := Retry(ctx, func(ctx context.Context) error {
var e error
resp, e = vpcClient.CreateVpc(req)
return e
})
if err != nil {
return Halt(state, err, "Failed to create vpc")
}
s.isCreate = true
s.VpcId = *resp.Response.Vpc.VpcId
state.Put("vpc_id", s.VpcId)
Message(state, s.VpcId, "Vpc created")
return multistep.ActionContinue
}
func (s *stepConfigVPC) Cleanup(state multistep.StateBag) {
if !s.isCreate {
return
}
ctx := context.TODO()
vpcClient := state.Get("vpc_client").(*vpc.Client)
ui := state.Get("ui").(packer.Ui)
MessageClean(state, "VPC")
SayClean(state, "vpc")
req := vpc.NewDeleteVpcRequest()
req.VpcId = &s.VpcId
err := retry.Config{
Tries: 60,
RetryDelay: (&retry.Backoff{InitialBackoff: 5 * time.Second, MaxBackoff: 5 * time.Second, Multiplier: 2}).Linear,
}.Run(ctx, func(ctx context.Context) error {
_, err := vpcClient.DeleteVpc(req)
return err
err := Retry(ctx, func(ctx context.Context) error {
_, e := vpcClient.DeleteVpc(req)
return e
})
if err != nil {
ui.Error(fmt.Sprintf("delete vpc(%s) failed: %s, you need to delete it by hand",
s.VpcId, err.Error()))
return
Error(state, err, fmt.Sprintf("Failed to delete vpc(%s), please delete it manually", s.VpcId))
}
}

View File

@ -2,10 +2,9 @@ package cvm
import (
"context"
"fmt"
"strings"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)
@ -20,9 +19,11 @@ func (s *stepCopyImage) Run(ctx context.Context, state multistep.StateBag) multi
}
client := state.Get("cvm_client").(*cvm.Client)
ui := state.Get("ui").(packer.Ui)
imageId := state.Get("image").(*cvm.Image).ImageId
Say(state, strings.Join(s.DesinationRegions, ","), "Trying to copy image to")
req := cvm.NewSyncImagesRequest()
req.ImageIds = []*string{imageId}
copyRegions := make([]*string, 0, len(s.DesinationRegions))
@ -33,15 +34,17 @@ func (s *stepCopyImage) Run(ctx context.Context, state multistep.StateBag) multi
}
req.DestinationRegions = copyRegions
_, err := client.SyncImages(req)
err := Retry(ctx, func(ctx context.Context) error {
_, e := client.SyncImages(req)
return e
})
if err != nil {
state.Put("error", err)
ui.Error(fmt.Sprintf("copy image failed: %s", err.Error()))
return multistep.ActionHalt
return Halt(state, err, "Failed to copy image")
}
Message(state, "Image copied", "")
return multistep.ActionContinue
}
func (s *stepCopyImage) Cleanup(state multistep.StateBag) {
// just do nothing
}
func (s *stepCopyImage) Cleanup(state multistep.StateBag) {}

View File

@ -3,12 +3,8 @@ package cvm
import (
"context"
"fmt"
"time"
"github.com/hashicorp/packer/common/retry"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)
@ -17,17 +13,18 @@ type stepCreateImage struct {
}
func (s *stepCreateImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
client := state.Get("cvm_client").(*cvm.Client)
ui := state.Get("ui").(packer.Ui)
config := state.Get("config").(*Config)
instance := state.Get("instance").(*cvm.Instance)
ui.Say(fmt.Sprintf("Creating image %s", config.ImageName))
Say(state, config.ImageName, "Trying to create a new image")
req := cvm.NewCreateImageRequest()
req.ImageName = &config.ImageName
req.ImageDescription = &config.ImageDescription
req.InstanceId = instance.InstanceId
// TODO: We should allow user to specify which data disk should be
// included into created image.
var dataDiskIds []*string
@ -46,51 +43,24 @@ func (s *stepCreateImage) Run(ctx context.Context, state multistep.StateBag) mul
req.ForcePoweroff = &False
}
if config.Reboot {
req.Reboot = &True
} else {
req.Reboot = &False
}
if config.Sysprep {
req.Sysprep = &True
} else {
req.Sysprep = &False
}
err := retry.Config{
Tries: 60,
RetryDelay: (&retry.Backoff{
InitialBackoff: 5 * time.Second,
MaxBackoff: 5 * time.Second,
Multiplier: 2,
}).Linear,
ShouldRetry: func(err error) bool {
if e, ok := err.(*errors.TencentCloudSDKError); ok {
if e.Code == "InvalidImageName.Duplicate" {
return false
}
}
return true
},
}.Run(ctx, func(ctx context.Context) error {
_, err := client.CreateImage(req)
return err
err := Retry(ctx, func(ctx context.Context) error {
_, e := client.CreateImage(req)
return e
})
if err != nil {
err := fmt.Errorf("create image failed: %s", err.Error())
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
return Halt(state, err, "Failed to create image")
}
Message(state, "Waiting for image ready", "")
err = WaitForImageReady(client, config.ImageName, "NORMAL", 3600)
if err != nil {
err := fmt.Errorf("create image failed: %s", err.Error())
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
return Halt(state, err, "Failed to wait for image ready")
}
describeReq := cvm.NewDescribeImagesRequest()
@ -101,21 +71,24 @@ func (s *stepCreateImage) Run(ctx context.Context, state multistep.StateBag) mul
Values: []*string{&config.ImageName},
},
}
describeResp, err := client.DescribeImages(describeReq)
var describeResp *cvm.DescribeImagesResponse
err = Retry(ctx, func(ctx context.Context) error {
var e error
describeResp, e = client.DescribeImages(describeReq)
return e
})
if err != nil {
err := fmt.Errorf("wait image ready failed: %s", err.Error())
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
return Halt(state, err, "Failed to wait for image ready")
}
if *describeResp.Response.TotalCount == 0 {
err := fmt.Errorf("create image(%s) failed", config.ImageName)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
return Halt(state, fmt.Errorf("No image return"), "Failed to crate image")
}
s.imageId = *describeResp.Response.ImageSet[0].ImageId
state.Put("image", describeResp.Response.ImageSet[0])
Message(state, s.imageId, "Image created")
tencentCloudImages := make(map[string]string)
tencentCloudImages[config.Region] = s.imageId
@ -128,20 +101,25 @@ func (s *stepCreateImage) Cleanup(state multistep.StateBag) {
if s.imageId == "" {
return
}
_, cancelled := state.GetOk(multistep.StateCancelled)
_, halted := state.GetOk(multistep.StateHalted)
if !cancelled && !halted {
return
}
ctx := context.TODO()
client := state.Get("cvm_client").(*cvm.Client)
ui := state.Get("ui").(packer.Ui)
ui.Say("Delete image because of cancellation or error...")
SayClean(state, "image")
req := cvm.NewDeleteImagesRequest()
req.ImageIds = []*string{&s.imageId}
_, err := client.DeleteImages(req)
err := Retry(ctx, func(ctx context.Context) error {
_, e := client.DeleteImages(req)
return e
})
if err != nil {
ui.Error(fmt.Sprintf("delete image(%s) failed", s.imageId))
Error(state, err, fmt.Sprintf("Failed to delete image(%s), please delete it manually", s.imageId))
}
}

View File

@ -2,12 +2,8 @@ package cvm
import (
"context"
"fmt"
"time"
"github.com/hashicorp/packer/common/retry"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)
@ -17,35 +13,31 @@ type stepDetachTempKeyPair struct {
func (s *stepDetachTempKeyPair) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("cvm_client").(*cvm.Client)
instance := state.Get("instance").(*cvm.Instance)
if _, ok := state.GetOk("temporary_key_pair_id"); !ok {
return multistep.ActionContinue
}
keyId := state.Get("temporary_key_pair_id").(*string)
ui := state.Get("ui").(packer.Ui)
ui.Say(fmt.Sprintf("Detaching temporary key pair %s...", *keyId))
keyId := state.Get("temporary_key_pair_id").(string)
instance := state.Get("instance").(*cvm.Instance)
Say(state, keyId, "Trying to detach keypair")
req := cvm.NewDisassociateInstancesKeyPairsRequest()
req.KeyIds = []*string{keyId}
req.KeyIds = []*string{&keyId}
req.InstanceIds = []*string{instance.InstanceId}
req.ForceStop = common.BoolPtr(true)
err := retry.Config{
Tries: 60,
RetryDelay: (&retry.Backoff{
InitialBackoff: 5 * time.Second,
MaxBackoff: 5 * time.Second,
Multiplier: 2,
}).Linear,
}.Run(ctx, func(ctx context.Context) error {
_, err := client.DisassociateInstancesKeyPairs(req)
return err
err := Retry(ctx, func(ctx context.Context) error {
_, e := client.DisassociateInstancesKeyPairs(req)
return e
})
if err != nil {
ui.Error(fmt.Sprintf("Fail to detach temporary key pair from instance! Error: %s", err))
state.Put("error", err)
return multistep.ActionHalt
return Halt(state, err, "Fail to detach keypair from instance")
}
Message(state, "Keypair detached", "")
return multistep.ActionContinue
}
func (s *stepDetachTempKeyPair) Cleanup(state multistep.StateBag) {
}
func (s *stepDetachTempKeyPair) Cleanup(state multistep.StateBag) {}

View File

@ -2,19 +2,45 @@ package cvm
import (
"context"
"fmt"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)
type stepPreValidate struct {
DestImageName string
ForceDelete bool
}
func (s *stepPreValidate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
ui.Say("TencentCloud support images with same name, image_name check is not required.")
config := state.Get("config").(*Config)
client := state.Get("cvm_client").(*cvm.Client)
Say(state, config.ImageName, "Trying to check image name")
req := cvm.NewDescribeImagesRequest()
req.Filters = []*cvm.Filter{
{
Name: common.StringPtr("image-name"),
Values: []*string{&config.ImageName},
},
}
var resp *cvm.DescribeImagesResponse
err := Retry(ctx, func(ctx context.Context) error {
var err error
resp, err = client.DescribeImages(req)
return err
})
if err != nil {
return Halt(state, err, "Failed to get images info")
}
if *resp.Response.TotalCount > 0 {
return Halt(state, fmt.Errorf("Image name %s has exists", config.ImageName), "")
}
Message(state, "useable", "Image name")
return multistep.ActionContinue
}

View File

@ -6,11 +6,8 @@ import (
"fmt"
"io/ioutil"
"log"
"time"
"github.com/hashicorp/packer/common/retry"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)
@ -32,8 +29,8 @@ type stepRunInstance struct {
func (s *stepRunInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
client := state.Get("cvm_client").(*cvm.Client)
config := state.Get("config").(*Config)
ui := state.Get("ui").(packer.Ui)
source_image := state.Get("source_image").(*cvm.Image)
vpc_id := state.Get("vpc_id").(string)
subnet_id := state.Get("subnet_id").(string)
@ -43,15 +40,14 @@ func (s *stepRunInstance) Run(ctx context.Context, state multistep.StateBag) mul
if password == "" && config.Comm.WinRMPassword != "" {
password = config.Comm.WinRMPassword
}
userData, err := s.getUserData(state)
if err != nil {
err := fmt.Errorf("get user_data failed: %s", err.Error())
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
return Halt(state, err, "Failed to get user_data")
}
ui.Say("Creating Instance.")
Say(state, "Trying to create a new instance", "")
// config RunInstances parameters
POSTPAID_BY_HOUR := "POSTPAID_BY_HOUR"
req := cvm.NewRunInstancesRequest()
@ -71,7 +67,7 @@ func (s *stepRunInstance) Run(ctx context.Context, state multistep.StateBag) mul
// System disk snapshot is mandatory, so if there are additional data disks,
// length will be larger than 1.
if source_image.SnapshotSet != nil && len(source_image.SnapshotSet) > 1 {
ui.Say("Use source image snapshot data disks, ignore user data disk settings.")
Message(state, "Use source image snapshot data disks, ignore user data disk settings", "")
var dataDisks []*cvm.DataDisk
for _, snapshot := range source_image.SnapshotSet {
if *snapshot.DiskUsage == "DATA_DISK" {
@ -144,44 +140,49 @@ func (s *stepRunInstance) Run(ctx context.Context, state multistep.StateBag) mul
}
}
resp, err := client.RunInstances(req)
var resp *cvm.RunInstancesResponse
err = Retry(ctx, func(ctx context.Context) error {
var e error
resp, e = client.RunInstances(req)
return e
})
if err != nil {
err := fmt.Errorf("create instance failed: %s", err.Error())
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
return Halt(state, err, "Failed to run instance")
}
if len(resp.Response.InstanceIdSet) != 1 {
err := fmt.Errorf("create instance failed: %d instance(s) created", len(resp.Response.InstanceIdSet))
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
return Halt(state, fmt.Errorf("No instance return"), "Failed to run instance")
}
s.instanceId = *resp.Response.InstanceIdSet[0]
Message(state, "Waiting for instance ready", "")
err = WaitForInstance(client, s.instanceId, "RUNNING", 1800)
if err != nil {
err := fmt.Errorf("wait instance launch failed: %s", err.Error())
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
return Halt(state, err, "Failed to wait for instance ready")
}
describeReq := cvm.NewDescribeInstancesRequest()
describeReq.InstanceIds = []*string{&s.instanceId}
describeResp, err := client.DescribeInstances(describeReq)
var describeResp *cvm.DescribeInstancesResponse
err = Retry(ctx, func(ctx context.Context) error {
var e error
describeResp, e = client.DescribeInstances(describeReq)
return e
})
if err != nil {
err := fmt.Errorf("wait instance launch failed: %s", err.Error())
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
return Halt(state, err, "Failed to wait for instance ready")
}
state.Put("instance", describeResp.Response.InstanceSet[0])
Message(state, s.instanceId, "Instance created")
return multistep.ActionContinue
}
func (s *stepRunInstance) getUserData(state multistep.StateBag) (string, error) {
userData := s.UserData
if userData == "" && s.UserDataFile != "" {
data, err := ioutil.ReadFile(s.UserDataFile)
if err != nil {
@ -189,8 +190,10 @@ func (s *stepRunInstance) getUserData(state multistep.StateBag) (string, error)
}
userData = string(data)
}
userData = base64.StdEncoding.EncodeToString([]byte(userData))
log.Printf(fmt.Sprintf("user_data: %s", userData))
log.Printf(fmt.Sprintf("[DEBUG]getUserData: user_data: %s", userData))
return userData, nil
}
@ -198,24 +201,19 @@ func (s *stepRunInstance) Cleanup(state multistep.StateBag) {
if s.instanceId == "" {
return
}
MessageClean(state, "Instance")
ctx := context.TODO()
client := state.Get("cvm_client").(*cvm.Client)
ui := state.Get("ui").(packer.Ui)
SayClean(state, "instance")
req := cvm.NewTerminateInstancesRequest()
req.InstanceIds = []*string{&s.instanceId}
ctx := context.TODO()
err := retry.Config{
Tries: 60,
RetryDelay: (&retry.Backoff{
InitialBackoff: 5 * time.Second,
MaxBackoff: 5 * time.Second,
Multiplier: 2,
}).Linear,
}.Run(ctx, func(ctx context.Context) error {
_, err := client.TerminateInstances(req)
return err
err := Retry(ctx, func(ctx context.Context) error {
_, e := client.TerminateInstances(req)
return e
})
if err != nil {
ui.Error(fmt.Sprintf("terminate instance(%s) failed: %s", s.instanceId, err.Error()))
Error(state, err, fmt.Sprintf("Failed to terminate instance(%s), please delete it manually", s.instanceId))
}
}

View File

@ -3,9 +3,10 @@ package cvm
import (
"context"
"fmt"
"strings"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)
@ -19,50 +20,57 @@ func (s *stepShareImage) Run(ctx context.Context, state multistep.StateBag) mult
}
client := state.Get("cvm_client").(*cvm.Client)
ui := state.Get("ui").(packer.Ui)
imageId := state.Get("image").(*cvm.Image).ImageId
Say(state, strings.Join(s.ShareAccounts, ","), "Trying to share image to")
req := cvm.NewModifyImageSharePermissionRequest()
req.ImageId = imageId
SHARE := "SHARE"
req.Permission = &SHARE
req.Permission = common.StringPtr("SHARE")
accounts := make([]*string, 0, len(s.ShareAccounts))
for _, account := range s.ShareAccounts {
accounts = append(accounts, &account)
}
req.AccountIds = accounts
_, err := client.ModifyImageSharePermission(req)
err := Retry(ctx, func(ctx context.Context) error {
_, e := client.ModifyImageSharePermission(req)
return e
})
if err != nil {
state.Put("error", err)
ui.Error(fmt.Sprintf("share image failed: %s", err.Error()))
return multistep.ActionHalt
return Halt(state, err, "Failed to share image")
}
Message(state, "Image shared", "")
return multistep.ActionContinue
}
func (s *stepShareImage) Cleanup(state multistep.StateBag) {
_, cancelled := state.GetOk(multistep.StateCancelled)
_, halted := state.GetOk(multistep.StateHalted)
if cancelled || halted {
ui := state.Get("ui").(packer.Ui)
client := state.Get("cvm_client").(*cvm.Client)
imageId := state.Get("image").(*cvm.Image).ImageId
ui.Say("Cancel share image due to action cancelled or halted.")
if !cancelled && !halted {
return
}
req := cvm.NewModifyImageSharePermissionRequest()
req.ImageId = imageId
CANCEL := "CANCEL"
req.Permission = &CANCEL
accounts := make([]*string, 0, len(s.ShareAccounts))
for _, account := range s.ShareAccounts {
accounts = append(accounts, &account)
}
req.AccountIds = accounts
ctx := context.TODO()
client := state.Get("cvm_client").(*cvm.Client)
_, err := client.ModifyImageSharePermission(req)
if err != nil {
ui.Error(fmt.Sprintf("Cancel share image failed: %s", err.Error()))
}
imageId := state.Get("image").(*cvm.Image).ImageId
SayClean(state, "image share")
req := cvm.NewModifyImageSharePermissionRequest()
req.ImageId = imageId
req.Permission = common.StringPtr("CANCEL")
accounts := make([]*string, 0, len(s.ShareAccounts))
for _, account := range s.ShareAccounts {
accounts = append(accounts, &account)
}
req.AccountIds = accounts
err := Retry(ctx, func(ctx context.Context) error {
_, e := client.ModifyImageSharePermission(req)
return e
})
if err != nil {
Error(state, err, fmt.Sprintf("Failed to cancel share image(%s), please delete it manually", *imageId))
}
}

View File

@ -3,32 +3,38 @@
"secret_id": "{{env `TENCENTCLOUD_ACCESS_KEY`}}",
"secret_key": "{{env `TENCENTCLOUD_SECRET_KEY`}}"
},
"builders": [{
"type": "tencentcloud-cvm",
"secret_id": "{{user `secret_id`}}",
"secret_key": "{{user `secret_key`}}",
"region": "ap-guangzhou",
"zone": "ap-guangzhou-4",
"instance_type": "S4.SMALL1",
"source_image_id": "img-oikl1tzv",
"ssh_username" : "root",
"image_name": "PackerTest",
"disk_type": "CLOUD_PREMIUM",
"packer_debug": true,
"associate_public_ip_address": true,
"run_tags": {
"good": "luck"
},
"data_disks": [{
"disk_type": "CLOUD_PREMIUM",
"disk_size": 50
}]
}],
"provisioners": [{
"type": "shell",
"inline": [
"sleep 30",
"yum install redis.x86_64 -y"
]
}]
}
"builders": [
{
"type": "tencentcloud-cvm",
"secret_id": "{{user `secret_id`}}",
"secret_key": "{{user `secret_key`}}",
"region": "ap-guangzhou",
"zone": "ap-guangzhou-4",
"instance_type": "S4.SMALL1",
"source_image_id": "img-oikl1tzv",
"ssh_username": "root",
"image_name": "PackerTest",
"disk_type": "CLOUD_PREMIUM",
"packer_debug": true,
"associate_public_ip_address": true,
"data_disks": [
{
"disk_type": "CLOUD_PREMIUM",
"disk_size": 50
}
],
"run_tags": {
"good": "luck"
}
}
],
"provisioners": [
{
"type": "shell",
"inline": [
"sleep 30",
"yum install redis.x86_64 -y"
]
}
]
}

View File

@ -3,28 +3,32 @@
"secret_id": "{{env `TENCENTCLOUD_ACCESS_KEY`}}",
"secret_key": "{{env `TENCENTCLOUD_SECRET_KEY`}}"
},
"builders": [{
"type": "tencentcloud-cvm",
"secret_id": "{{user `secret_id`}}",
"secret_key": "{{user `secret_key`}}",
"region": "ap-guangzhou",
"zone": "ap-guangzhou-4",
"instance_type": "S4.SMALL1",
"source_image_id": "img-oikl1tzv",
"ssh_username" : "root",
"image_name": "PackerTest",
"disk_type": "CLOUD_PREMIUM",
"packer_debug": true,
"associate_public_ip_address": true,
"run_tags": {
"good": "luck"
"builders": [
{
"type": "tencentcloud-cvm",
"secret_id": "{{user `secret_id`}}",
"secret_key": "{{user `secret_key`}}",
"region": "ap-guangzhou",
"zone": "ap-guangzhou-4",
"instance_type": "S4.SMALL1",
"source_image_id": "img-oikl1tzv",
"ssh_username": "root",
"image_name": "PackerTest",
"disk_type": "CLOUD_PREMIUM",
"packer_debug": true,
"associate_public_ip_address": true,
"run_tags": {
"good": "luck"
}
}
}],
"provisioners": [{
"type": "shell",
"inline": [
"sleep 30",
"yum install redis.x86_64 -y"
]
}]
}
],
"provisioners": [
{
"type": "shell",
"inline": [
"sleep 30",
"yum install redis.x86_64 -y"
]
}
]
}

View File

@ -3,33 +3,40 @@
"secret_id": "{{env `TENCENTCLOUD_ACCESS_KEY`}}",
"secret_key": "{{env `TENCENTCLOUD_SECRET_KEY`}}"
},
"builders": [{
"type": "tencentcloud-cvm",
"secret_id": "{{user `secret_id`}}",
"secret_key": "{{user `secret_key`}}",
"region": "ap-guangzhou",
"zone": "ap-guangzhou-3",
"instance_type": "S3.SMALL1",
"source_image_id": "img-oikl1tzv",
"vpc_id": "vpc-gjusx3kd",
"subnet_id": "subnet-pfditepm",
"internet_max_bandwidth_out": 2,
"security_group_id": "sg-rypoiksl",
"ssh_username" : "root",
"image_name": "packerTest",
"host_name": "packerTest",
"associate_public_ip_address": true,
"image_description": "centosPacker",
"image_copy_regions": ["ap-beijing"]
}],
"provisioners": [{
"execute_command": "echo '{{user `ssh_pass`}}' | {{ .Vars }} sudo -S -E sh '{{ .Path }}'",
"inline": [
"yum update -y",
"/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync"
],
"inline_shebang": "/bin/sh -x",
"type": "shell",
"skip_clean": true
}]
"builders": [
{
"type": "tencentcloud-cvm",
"secret_id": "{{user `secret_id`}}",
"secret_key": "{{user `secret_key`}}",
"region": "ap-guangzhou",
"zone": "ap-guangzhou-3",
"instance_type": "S3.SMALL1",
"source_image_id": "img-oikl1tzv",
"disk_type": "CLOUD_PREMIUM",
"vpc_id": "vpc-h70b6b49",
"subnet_id": "subnet-1uwh63so",
"internet_max_bandwidth_out": 2,
"security_group_id": "sg-nltpbqg1",
"ssh_username": "root",
"image_name": "packerTest",
"host_name": "packerTest",
"associate_public_ip_address": true,
"image_description": "centosPacker",
"image_copy_regions": [
"ap-beijing"
]
}
],
"provisioners": [
{
"execute_command": "echo '{{user `ssh_pass`}}' | {{ .Vars }} sudo -S -E sh '{{ .Path }}'",
"inline": [
"yum update -y",
"/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync"
],
"inline_shebang": "/bin/sh -x",
"type": "shell",
"skip_clean": true
}
]
}

2
go.mod
View File

@ -132,7 +132,7 @@ require (
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c // indirect
github.com/stretchr/testify v1.4.0
github.com/temoto/robotstxt v1.1.1 // indirect
github.com/tencentcloud/tencentcloud-sdk-go v3.0.71+incompatible
github.com/tencentcloud/tencentcloud-sdk-go v3.0.94+incompatible
github.com/ucloud/ucloud-sdk-go v0.8.7
github.com/ugorji/go v0.0.0-20151218193438-646ae4a518c1
github.com/ulikunitz/xz v0.5.5

4
go.sum
View File

@ -395,8 +395,8 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/temoto/robotstxt v1.1.1 h1:Gh8RCs8ouX3hRSxxK7B1mO5RFByQ4CmJZDwgom++JaA=
github.com/temoto/robotstxt v1.1.1/go.mod h1:+1AmkuG3IYkh1kv0d2qEB9Le88ehNO0zwOr3ujewlOo=
github.com/tencentcloud/tencentcloud-sdk-go v3.0.71+incompatible h1:9sIWfe6ZC7xoSlshYWNGicPqomK7N+CsHMa1YFWBCWU=
github.com/tencentcloud/tencentcloud-sdk-go v3.0.71+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4=
github.com/tencentcloud/tencentcloud-sdk-go v3.0.94+incompatible h1:G8i7dPMK1RCpbQz+VpfFp679vmVna38NI8tz5xsybXI=
github.com/tencentcloud/tencentcloud-sdk-go v3.0.94+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4=
github.com/ucloud/ucloud-sdk-go v0.8.7 h1:BmXOb5RivI0Uu4oZRpjI6SQ9/y7n/H9wxTGR1txIE8o=
github.com/ucloud/ucloud-sdk-go v0.8.7/go.mod h1:lM6fpI8y6iwACtlbHUav823/uKPdXsNBlnBpRF2fj3c=
github.com/ugorji/go v0.0.0-20151218193438-646ae4a518c1 h1:U6ufy3mLDgg9RYupntOvAF7xCmNNquyKaYaaVHo1Nnk=

View File

@ -6,10 +6,12 @@ import (
"fmt"
"log"
"net/http"
"net/http/httputil"
"strconv"
"strings"
"time"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
tchttp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
)
@ -18,6 +20,7 @@ type Client struct {
region string
httpClient *http.Client
httpProfile *profile.HttpProfile
profile *profile.ClientProfile
credential *Credential
signMethod string
unsignedPayload bool
@ -47,6 +50,8 @@ func (c *Client) Send(request tchttp.Request, response tchttp.Response) (err err
}
func (c *Client) sendWithSignatureV1(request tchttp.Request, response tchttp.Response) (err error) {
// TODO: not an elegant way, it should be done in common params, but finally it need to refactor
request.GetParams()["Language"] = c.profile.Language
err = tchttp.ConstructParams(request)
if err != nil {
return err
@ -62,10 +67,18 @@ func (c *Client) sendWithSignatureV1(request tchttp.Request, response tchttp.Res
if request.GetHttpMethod() == "POST" {
httpRequest.Header["Content-Type"] = []string{"application/x-www-form-urlencoded"}
}
//log.Printf("[DEBUG] http request=%v", httpRequest)
if c.debug {
outbytes, err := httputil.DumpRequest(httpRequest, true)
if err != nil {
log.Printf("[ERROR] dump request failed because %s", err)
return err
}
log.Printf("[DEBUG] http request = %s", outbytes)
}
httpResponse, err := c.httpClient.Do(httpRequest)
if err != nil {
return err
msg := fmt.Sprintf("Fail to get response because %s", err)
return errors.NewTencentCloudSDKError("ClientError.NetworkError", msg, "")
}
err = tchttp.ParseFromHttpResponse(httpResponse, response)
return err
@ -78,6 +91,7 @@ func (c *Client) sendWithSignatureV3(request tchttp.Request, response tchttp.Res
"X-TC-Version": request.GetVersion(),
"X-TC-Timestamp": request.GetParams()["Timestamp"],
"X-TC-RequestClient": request.GetParams()["RequestClient"],
"X-TC-Language": c.profile.Language,
}
if c.region != "" {
headers["X-TC-Region"] = c.region
@ -184,10 +198,18 @@ func (c *Client) sendWithSignatureV3(request tchttp.Request, response tchttp.Res
for k, v := range headers {
httpRequest.Header[k] = []string{v}
}
//log.Printf("[DEBUG] http request=%v, body=%v", httpRequest, requestPayload)
if c.debug {
outbytes, err := httputil.DumpRequest(httpRequest, true)
if err != nil {
log.Printf("[ERROR] dump request failed because %s", err)
return err
}
log.Printf("[DEBUG] http request = %s", outbytes)
}
httpResponse, err := c.httpClient.Do(httpRequest)
if err != nil {
return err
msg := fmt.Sprintf("Fail to get response because %s", err)
return errors.NewTencentCloudSDKError("ClientError.NetworkError", msg, "")
}
err = tchttp.ParseFromHttpResponse(httpResponse, response)
return err
@ -200,7 +222,7 @@ func (c *Client) GetRegion() string {
func (c *Client) Init(region string) *Client {
c.httpClient = &http.Client{}
c.region = region
c.signMethod = "HmacSHA256"
c.signMethod = "TC3-HMAC-SHA256"
c.debug = false
log.SetFlags(log.LstdFlags | log.Lshortfile)
return c
@ -217,6 +239,7 @@ func (c *Client) WithCredential(cred *Credential) *Client {
}
func (c *Client) WithProfile(clientProfile *profile.ClientProfile) *Client {
c.profile = clientProfile
c.signMethod = clientProfile.SignMethod
c.unsignedPayload = clientProfile.UnsignedPayload
c.httpProfile = clientProfile.HttpProfile
@ -229,7 +252,7 @@ func (c *Client) WithSignatureMethod(method string) *Client {
return c
}
func (c *Client) WithHttpTransport (transport http.RoundTripper) *Client {
func (c *Client) WithHttpTransport(transport http.RoundTripper) *Client {
c.httpClient.Transport = transport
return c
}

View File

@ -152,7 +152,7 @@ func CompleteCommonParams(request Request, region string) {
params["Action"] = request.GetAction()
params["Timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
params["Nonce"] = strconv.Itoa(rand.Int())
params["RequestClient"] = "SDK_GO_3.0.71"
params["RequestClient"] = "SDK_GO_3.0.94"
}
func ConstructParams(req Request) (err error) {
@ -195,8 +195,9 @@ func flatStructure(value reflect.Value, request Request, prefix string) (err err
} else if kind == reflect.Float64 {
request.GetParams()[key] = strconv.FormatFloat(field.Float(), 'f', -1, 64)
} else if kind == reflect.Slice {
for j := 0; j < field.Len(); j++ {
vj := field.Index(j)
list := value.Field(i)
for j := 0; j < list.Len(); j++ {
vj := list.Index(j)
key := prefix + nameTag + "." + strconv.Itoa(j)
kind = vj.Kind()
if kind == reflect.Ptr && vj.IsNil() {
@ -217,11 +218,15 @@ func flatStructure(value reflect.Value, request Request, prefix string) (err err
} else if kind == reflect.Float64 {
request.GetParams()[key] = strconv.FormatFloat(vj.Float(), 'f', -1, 64)
} else {
return flatStructure(vj, request, key+".")
if err = flatStructure(vj, request, key+"."); err != nil {
return
}
}
}
} else {
return flatStructure(reflect.ValueOf(field.Interface()), request, prefix+nameTag+".")
if err = flatStructure(reflect.ValueOf(field.Interface()), request, prefix+nameTag+"."); err != nil {
return
}
}
}
return

View File

@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
//"log"
"net/http"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
@ -37,7 +37,8 @@ func (r *BaseResponse) ParseErrorFromHTTPResponse(body []byte) (err error) {
resp := &ErrorResponse{}
err = json.Unmarshal(body, resp)
if err != nil {
return
msg := fmt.Sprintf("Fail to parse json content: %s, because: %s", body, err)
return errors.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
}
if resp.Response.Error.Code != "" {
return errors.NewTencentCloudSDKError(resp.Response.Error.Code, resp.Response.Error.Message, resp.Response.RequestId)
@ -46,7 +47,8 @@ func (r *BaseResponse) ParseErrorFromHTTPResponse(body []byte) (err error) {
deprecated := &DeprecatedAPIErrorResponse{}
err = json.Unmarshal(body, deprecated)
if err != nil {
return
msg := fmt.Sprintf("Fail to parse json content: %s, because: %s", body, err)
return errors.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
}
if deprecated.Code != 0 {
return errors.NewTencentCloudSDKError(deprecated.CodeDesc, deprecated.Message, "")
@ -58,10 +60,12 @@ func ParseFromHttpResponse(hr *http.Response, response Response) (err error) {
defer hr.Body.Close()
body, err := ioutil.ReadAll(hr.Body)
if err != nil {
return
msg := fmt.Sprintf("Fail to read response body because %s", err)
return errors.NewTencentCloudSDKError("ClientError.IOError", msg, "")
}
if hr.StatusCode != 200 {
return fmt.Errorf("Request fail with status: %s, with body: %s", hr.Status, body)
msg := fmt.Sprintf("Request fail with http status code: %s, with body: %s", hr.Status, body)
return errors.NewTencentCloudSDKError("ClientError.HttpStatusCodeError", msg, "")
}
//log.Printf("[DEBUG] Response Body=%s", body)
err = response.ParseErrorFromHTTPResponse(body)
@ -70,7 +74,8 @@ func ParseFromHttpResponse(hr *http.Response, response Response) (err error) {
}
err = json.Unmarshal(body, &response)
if err != nil {
log.Printf("Unexpected Error occurs when parsing API response\n%s\n", string(body[:]))
msg := fmt.Sprintf("Fail to parse json content: %s, because: %s", body, err)
return errors.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
}
return
}

View File

@ -1,9 +1,14 @@
package profile
type ClientProfile struct {
HttpProfile *HttpProfile
HttpProfile *HttpProfile
// Valid choices: HmacSHA1, HmacSHA256, TC3-HMAC-SHA256.
// Default value is TC3-HMAC-SHA256.
SignMethod string
UnsignedPayload bool
// Valid choices: zh-CN, en-US.
// Default value is zh-CN.
Language string
}
func NewClientProfile() *ClientProfile {
@ -11,5 +16,6 @@ func NewClientProfile() *ClientProfile {
HttpProfile: NewHttpProfile(),
SignMethod: "TC3-HMAC-SHA256",
UnsignedPayload: false,
Language: "zh-CN",
}
}

View File

@ -4,7 +4,9 @@ type HttpProfile struct {
ReqMethod string
ReqTimeout int
Endpoint string
Protocol string
// Deprecated, use Scheme instead
Protocol string
Scheme string
}
func NewHttpProfile() *HttpProfile {
@ -12,6 +14,6 @@ func NewHttpProfile() *HttpProfile {
ReqMethod: "POST",
ReqTimeout: 60,
Endpoint: "",
Protocol: "HTTPS",
Scheme: "HTTPS",
}
}

View File

@ -1,14 +1,13 @@
package common
import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"fmt"
"sort"
"strings"
tchttp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
)
@ -65,7 +64,11 @@ func getStringToSign(request tchttp.Request) string {
domain := request.GetDomain()
path := request.GetPath()
text := method + domain + path + "?"
var buf bytes.Buffer
buf.WriteString(method)
buf.WriteString(domain)
buf.WriteString(path)
buf.WriteString("?")
params := request.GetParams()
// sort params
@ -77,11 +80,15 @@ func getStringToSign(request tchttp.Request) string {
for i := range keys {
k := keys[i]
// TODO: check if server side allows empty value in url.
if params[k] == "" {
continue
}
text += fmt.Sprintf("%v=%v&", strings.Replace(k, "_", ".", -1), params[k])
buf.WriteString(k)
buf.WriteString("=")
buf.WriteString(params[k])
buf.WriteString("&")
}
text = text[:len(text)-1]
return text
buf.Truncate(buf.Len() - 1)
return buf.String()
}

View File

@ -743,6 +743,56 @@ func (c *Client) DescribeRegions(request *DescribeRegionsRequest) (response *Des
return
}
func NewDescribeReservedInstancesRequest() (request *DescribeReservedInstancesRequest) {
request = &DescribeReservedInstancesRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("cvm", APIVersion, "DescribeReservedInstances")
return
}
func NewDescribeReservedInstancesResponse() (response *DescribeReservedInstancesResponse) {
response = &DescribeReservedInstancesResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口(DescribeReservedInstances)可提供列出用户已购买的预留实例
func (c *Client) DescribeReservedInstances(request *DescribeReservedInstancesRequest) (response *DescribeReservedInstancesResponse, err error) {
if request == nil {
request = NewDescribeReservedInstancesRequest()
}
response = NewDescribeReservedInstancesResponse()
err = c.Send(request, response)
return
}
func NewDescribeReservedInstancesOfferingsRequest() (request *DescribeReservedInstancesOfferingsRequest) {
request = &DescribeReservedInstancesOfferingsRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("cvm", APIVersion, "DescribeReservedInstancesOfferings")
return
}
func NewDescribeReservedInstancesOfferingsResponse() (response *DescribeReservedInstancesOfferingsResponse) {
response = &DescribeReservedInstancesOfferingsResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口(DescribeReservedInstancesOfferings)供用户列出可购买的预留实例配置
func (c *Client) DescribeReservedInstancesOfferings(request *DescribeReservedInstancesOfferingsRequest) (response *DescribeReservedInstancesOfferingsResponse, err error) {
if request == nil {
request = NewDescribeReservedInstancesOfferingsRequest()
}
response = NewDescribeReservedInstancesOfferingsResponse()
err = c.Send(request, response)
return
}
func NewDescribeZoneInstanceConfigInfosRequest() (request *DescribeZoneInstanceConfigInfosRequest) {
request = &DescribeZoneInstanceConfigInfosRequest{
BaseRequest: &tchttp.BaseRequest{},
@ -863,7 +913,7 @@ func NewImportImageResponse() (response *ImportImageResponse) {
return
}
// 本接口(ImportImage)用于导入镜像,导入后的镜像可用于创建实例。
// 本接口(ImportImage)用于导入镜像,导入后的镜像可用于创建实例。
func (c *Client) ImportImage(request *ImportImageRequest) (response *ImportImageResponse, err error) {
if request == nil {
request = NewImportImageRequest()
@ -972,7 +1022,11 @@ func NewInquiryPriceResetInstanceResponse() (response *InquiryPriceResetInstance
return
}
// 本接口 (InquiryPriceResetInstance) 用于重装实例询价。* 如果指定了`ImageId`参数,则使用指定的镜像进行重装询价;否则按照当前实例使用的镜像进行重装询价。* 目前只支持[系统盘类型](/document/api/213/9452#block_device)是`CLOUD_BASIC`、`CLOUD_PREMIUM`、`CLOUD_SSD`类型的实例使用该接口实现`Linux`和`Windows`操作系统切换的重装询价。* 目前不支持海外地域的实例使用该接口实现`Linux`和`Windows`操作系统切换的重装询价。
// 本接口 (InquiryPriceResetInstance) 用于重装实例询价。
//
// * 如果指定了`ImageId`参数,则使用指定的镜像进行重装询价;否则按照当前实例使用的镜像进行重装询价。
// * 目前只支持[系统盘类型](/document/api/213/9452#block_device)是`CLOUD_BASIC`、`CLOUD_PREMIUM`、`CLOUD_SSD`类型的实例使用该接口实现`Linux`和`Windows`操作系统切换的重装询价。
// * 目前不支持海外地域的实例使用该接口实现`Linux`和`Windows`操作系统切换的重装询价。
func (c *Client) InquiryPriceResetInstance(request *InquiryPriceResetInstanceRequest) (response *InquiryPriceResetInstanceResponse, err error) {
if request == nil {
request = NewInquiryPriceResetInstanceRequest()
@ -1374,6 +1428,31 @@ func (c *Client) ModifyKeyPairAttribute(request *ModifyKeyPairAttributeRequest)
return
}
func NewPurchaseReservedInstancesOfferingRequest() (request *PurchaseReservedInstancesOfferingRequest) {
request = &PurchaseReservedInstancesOfferingRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("cvm", APIVersion, "PurchaseReservedInstancesOffering")
return
}
func NewPurchaseReservedInstancesOfferingResponse() (response *PurchaseReservedInstancesOfferingResponse) {
response = &PurchaseReservedInstancesOfferingResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口(PurchaseReservedInstancesOffering)用于用户购买一个或者多个指定配置的预留实例
func (c *Client) PurchaseReservedInstancesOffering(request *PurchaseReservedInstancesOfferingRequest) (response *PurchaseReservedInstancesOfferingResponse, err error) {
if request == nil {
request = NewPurchaseReservedInstancesOfferingRequest()
}
response = NewPurchaseReservedInstancesOfferingResponse()
err = c.Send(request, response)
return
}
func NewRebootInstancesRequest() (request *RebootInstancesRequest) {
request = &RebootInstancesRequest{
BaseRequest: &tchttp.BaseRequest{},

View File

@ -243,19 +243,17 @@ type CreateImageRequest struct {
// 镜像描述
ImageDescription *string `json:"ImageDescription,omitempty" name:"ImageDescription"`
// 软关机失败时是否执行强制关机以制作镜像
// 是否执行强制关机以制作镜像。
// 取值范围:<br><li>TRUE表示关机之后制作镜像<br><li>FALSE表示开机状态制作镜像<br><br>默认取值FALSE。<br><br>开机状态制作镜像,可能导致部分数据未备份,影响数据安全。
ForcePoweroff *string `json:"ForcePoweroff,omitempty" name:"ForcePoweroff"`
// 创建Windows镜像时是否启用Sysprep
Sysprep *string `json:"Sysprep,omitempty" name:"Sysprep"`
// 实例处于运行中时,是否允许关机执行制作镜像任务。
Reboot *string `json:"Reboot,omitempty" name:"Reboot"`
// 实例需要制作镜像的数据盘Id
DataDiskIds []*string `json:"DataDiskIds,omitempty" name:"DataDiskIds" list`
// 需要制作镜像的快照Id,必须包含一个系统盘快照
// 需要制作镜像的快照ID,必须包含一个系统盘快照
SnapshotIds []*string `json:"SnapshotIds,omitempty" name:"SnapshotIds" list`
// 检测请求的合法性,但不会对操作的资源产生任何影响
@ -683,8 +681,11 @@ type DescribeImagesRequest struct {
// 过滤条件,每次请求的`Filters`的上限为0`Filters.Values`的上限为5。参数不可以同时指定`ImageIds`和`Filters`。详细的过滤条件如下:
// <li> image-id - String - 是否必填: 否 - 过滤条件按照镜像ID进行过滤</li>
// <li> image-type - String - 是否必填: 否 - (过滤条件)按照镜像类型进行过滤。取值范围:详见[镜像类型](https://cloud.tencent.com/document/product/213/9452#image_type)。</li>
// <li> image-state - String - 是否必填: 否 - (过滤条件)按照镜像状态进行过滤。取值范围:详见[镜像状态](https://cloud.tencent.com/document/product/213/9452#image_state)。</li>
// <li> image-type - String - 是否必填: 否 - (过滤条件)按照镜像类型进行过滤。取值范围:
// PRIVATE_IMAGE: 私有镜像 (本帐户创建的镜像)
// PUBLIC_IMAGE: 公共镜像 (腾讯云官方镜像)
// MARKET_IMAGE: 服务市场 (服务市场提供的镜像)
// SHARED_IMAGE: 共享镜像(其他账户共享给本帐户的镜像) 。</li>
Filters []*Filter `json:"Filters,omitempty" name:"Filters" list`
// 偏移量默认为0。关于Offset详见[API简介](/document/api/213/568#.E8.BE.93.E5.85.A5.E5.8F.82.E6.95.B0.E4.B8.8E.E8.BF.94.E5.9B.9E.E5.8F.82.E6.95.B0.E9.87.8A.E4.B9.89)。
@ -1188,6 +1189,140 @@ func (r *DescribeRegionsResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeReservedInstancesOfferingsRequest struct {
*tchttp.BaseRequest
// 试运行, 默认为 false。
DryRun *bool `json:"DryRun,omitempty" name:"DryRun"`
// 偏移量默认为0。关于`Offset`的更进一步介绍请参考 API [简介](https://cloud.tencent.com/document/api/213/15688)中的相关小节。
Offset *int64 `json:"Offset,omitempty" name:"Offset"`
// 返回数量默认为20最大值为100。关于`Limit`的更进一步介绍请参考 API [简介](https://cloud.tencent.com/document/api/213/15688)中的相关小节。
Limit *int64 `json:"Limit,omitempty" name:"Limit"`
// 以最大有效期作为过滤参数。
// 计量单位: 秒
// 默认为 94608000。
MaxDuration *int64 `json:"MaxDuration,omitempty" name:"MaxDuration"`
// 以最小有效期作为过滤参数。
// 计量单位: 秒
// 默认为 2592000。
MinDuration *int64 `json:"MinDuration,omitempty" name:"MinDuration"`
// <li><strong>zone</strong></li>
// <p style="padding-left: 30px;">按照预留实例计费可购买的【<strong>可用区</strong>】进行过滤。形如ap-guangzhou-1。</p><p style="padding-left: 30px;">类型String</p><p style="padding-left: 30px;">必选:否</p><p style="padding-left: 30px;">可选项:<a href="https://cloud.tencent.com/document/product/213/6091">可用区列表</a></p>
// <li><strong>duration</strong></li>
// <p style="padding-left: 30px;">按照预留实例计费【<strong>有效期</strong>】即预留实例计费购买时长进行过滤。形如31536000。</p><p style="padding-left: 30px;">类型Integer</p><p style="padding-left: 30px;">计量单位:秒</p><p style="padding-left: 30px;">必选:否</p><p style="padding-left: 30px;">可选项31536000 (1年) | 946080003年</p>
// <li><strong>instance-type</strong></li>
// <p style="padding-left: 30px;">按照【<strong>预留实例计费类型</strong>】进行过滤。形如S3.MEDIUM4。</p><p style="padding-left: 30px;">类型String</p><p style="padding-left: 30px;">必选:否</p><p style="padding-left: 30px;">可选项:<a href="https://cloud.tencent.com/document/product/213/11518">预留实例计费类型列表</a></p>
// <li><strong>offering-type</strong></li>
// <p style="padding-left: 30px;">按照【<strong>付款类型</strong>】进行过滤。形如All Upfront (预付全部费用)。</p><p style="padding-left: 30px;">类型String</p><p style="padding-left: 30px;">必选:否</p><p style="padding-left: 30px;">可选项All Upfront (预付全部费用)</p>
// <li><strong>product-description</strong></li>
// <p style="padding-left: 30px;">按照预留实例计费的【<strong>平台描述</strong>】即操作系统进行过滤。形如linux。</p><p style="padding-left: 30px;">类型String</p><p style="padding-left: 30px;">必选:否</p><p style="padding-left: 30px;">可选项linux</p>
// <li><strong>reserved-instances-offering-id</strong></li>
// <p style="padding-left: 30px;">按照【<strong>预留实例计费配置ID</strong>】进行过滤。形如650c138f-ae7e-4750-952a-96841d6e9fc1。</p><p style="padding-left: 30px;">类型String</p><p style="padding-left: 30px;">必选:否</p>
// 每次请求的`Filters`的上限为10`Filter.Values`的上限为5。
Filters []*Filter `json:"Filters,omitempty" name:"Filters" list`
}
func (r *DescribeReservedInstancesOfferingsRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DescribeReservedInstancesOfferingsRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeReservedInstancesOfferingsResponse struct {
*tchttp.BaseResponse
Response *struct {
// 符合条件的预留实例计费数量。
TotalCount *int64 `json:"TotalCount,omitempty" name:"TotalCount"`
// 符合条件的预留实例计费列表。
ReservedInstancesOfferingsSet []*ReservedInstancesOffering `json:"ReservedInstancesOfferingsSet,omitempty" name:"ReservedInstancesOfferingsSet" list`
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *DescribeReservedInstancesOfferingsResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DescribeReservedInstancesOfferingsResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeReservedInstancesRequest struct {
*tchttp.BaseRequest
// 试运行。默认为 false。
DryRun *bool `json:"DryRun,omitempty" name:"DryRun"`
// 偏移量默认为0。关于`Offset`的更进一步介绍请参考 API [简介](https://cloud.tencent.com/document/api/213/15688)中的相关小节。
Offset *int64 `json:"Offset,omitempty" name:"Offset"`
// 返回数量默认为20最大值为100。关于`Limit`的更进一步介绍请参考 API [简介](https://cloud.tencent.com/document/api/213/15688)中的相关小节。
Limit *int64 `json:"Limit,omitempty" name:"Limit"`
// <li><strong>zone</strong></li>
// <p style="padding-left: 30px;">按照预留实例计费可购买的【<strong>可用区</strong>】进行过滤。形如ap-guangzhou-1。</p><p style="padding-left: 30px;">类型String</p><p style="padding-left: 30px;">必选:否</p><p style="padding-left: 30px;">可选项:<a href="https://cloud.tencent.com/document/product/213/6091">可用区列表</a></p>
// <li><strong>duration</strong></li>
// <p style="padding-left: 30px;">按照预留实例计费【<strong>有效期</strong>】即预留实例计费购买时长进行过滤。形如31536000。</p><p style="padding-left: 30px;">类型Integer</p><p style="padding-left: 30px;">计量单位:秒</p><p style="padding-left: 30px;">必选:否</p><p style="padding-left: 30px;">可选项31536000 (1年) | 946080003年</p>
// <li><strong>instance-type</strong></li>
// <p style="padding-left: 30px;">按照【<strong>预留实例计费类型</strong>】进行过滤。形如S3.MEDIUM4。</p><p style="padding-left: 30px;">类型String</p><p style="padding-left: 30px;">必选:否</p><p style="padding-left: 30px;">可选项:<a href="https://cloud.tencent.com/document/product/213/11518">预留实例计费类型列表</a></p>
// <li><strong>offering-type</strong></li>
// <p style="padding-left: 30px;">按照【<strong>付款类型</strong>】进行过滤。形如All Upfront (预付全部费用)。</p><p style="padding-left: 30px;">类型String</p><p style="padding-left: 30px;">必选:否</p><p style="padding-left: 30px;">可选项All Upfront (预付全部费用)</p>
// <li><strong>product-description</strong></li>
// <p style="padding-left: 30px;">按照预留实例计费的【<strong>平台描述</strong>】即操作系统进行过滤。形如linux。</p><p style="padding-left: 30px;">类型String</p><p style="padding-left: 30px;">必选:否</p><p style="padding-left: 30px;">可选项linux</p>
// <li><strong>reserved-instances-id</strong></li>
// <p style="padding-left: 30px;">按照已购买【<strong>预留实例计费ID</strong>】进行过滤。形如650c138f-ae7e-4750-952a-96841d6e9fc1。</p><p style="padding-left: 30px;">类型String</p><p style="padding-left: 30px;">必选:否</p>
// <li><strong>state</strong></li>
// <p style="padding-left: 30px;">按照已购买【<strong>预留实例计费状态</strong>】进行过滤。形如active。</p><p style="padding-left: 30px;">类型String</p><p style="padding-left: 30px;">必选:否</p><p style="padding-left: 30px;">可选项active (以创建) | pending (等待被创建) | retired (过期)</p>
// 每次请求的`Filters`的上限为10`Filter.Values`的上限为5。
Filters []*Filter `json:"Filters,omitempty" name:"Filters" list`
}
func (r *DescribeReservedInstancesRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DescribeReservedInstancesRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeReservedInstancesResponse struct {
*tchttp.BaseResponse
Response *struct {
// 符合条件的预留实例计费数量。
TotalCount *int64 `json:"TotalCount,omitempty" name:"TotalCount"`
// 符合条件的预留实例计费列表。
ReservedInstancesSet []*ReservedInstances `json:"ReservedInstancesSet,omitempty" name:"ReservedInstancesSet" list`
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *DescribeReservedInstancesResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DescribeReservedInstancesResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeZoneInstanceConfigInfosRequest struct {
*tchttp.BaseRequest
@ -2010,7 +2145,7 @@ type Instance struct {
// 实例名称。
InstanceName *string `json:"InstanceName,omitempty" name:"InstanceName"`
// 实例计费模式。取值范围:<br><li>`PREPAID`:表示预付费,即包年包月<br><li>`POSTPAID_BY_HOUR`:表示后付费,即按量计费<br><li>`CDHPAID``CDH`付费,即只对`CDH`计费,不对`CDH`上的实例计费。
// 实例计费模式。取值范围:<br><li>`PREPAID`:表示预付费,即包年包月<br><li>`POSTPAID_BY_HOUR`:表示后付费,即按量计费<br><li>`CDHPAID``CDH`付费,即只对`CDH`计费,不对`CDH`上的实例计费。<br><li>`SPOTPAID`:表示竞价实例付费。
InstanceChargeType *string `json:"InstanceChargeType,omitempty" name:"InstanceChargeType"`
// 实例系统盘信息。
@ -2062,6 +2197,24 @@ type Instance struct {
// 实例的关机计费模式。
// 取值范围:<br><li>KEEP_CHARGING关机继续收费<br><li>STOP_CHARGING关机停止收费<li>NOT_APPLICABLE实例处于非关机状态或者不适用关机停止计费的条件<br>
StopChargingMode *string `json:"StopChargingMode,omitempty" name:"StopChargingMode"`
// 实例全局唯一ID
Uuid *string `json:"Uuid,omitempty" name:"Uuid"`
// 实例的最新操作。例StopInstances、ResetInstance。
// 注意:此字段可能返回 null表示取不到有效值。
LatestOperation *string `json:"LatestOperation,omitempty" name:"LatestOperation"`
// 实例的最新操作状态。取值范围:<br>
// <li>SUCCESS表示操作成功<br>
// <li>OPERATING表示操作执行中<br>
// <li>FAILED表示操作失败
// 注意:此字段可能返回 null表示取不到有效值。
LatestOperationState *string `json:"LatestOperationState,omitempty" name:"LatestOperationState"`
// 实例最新操作的唯一请求 ID。
// 注意:此字段可能返回 null表示取不到有效值。
LatestOperationRequestId *string `json:"LatestOperationRequestId,omitempty" name:"LatestOperationRequestId"`
}
type InstanceChargePrepaid struct {
@ -2139,7 +2292,7 @@ type InstanceTypeQuotaItem struct {
// 实例机型。
InstanceType *string `json:"InstanceType,omitempty" name:"InstanceType"`
// 实例计费模式。取值范围: <br><li>PREPAID表示预付费即包年包月<br><li>POSTPAID_BY_HOUR表示后付费即按量计费<br><li>CDHPAID表示[CDH](https://cloud.tencent.com/document/product/416)付费即只对CDH计费不对CDH上的实例计费。
// 实例计费模式。取值范围: <br><li>PREPAID表示预付费即包年包月<br><li>POSTPAID_BY_HOUR表示后付费即按量计费<br><li>CDHPAID表示[CDH](https://cloud.tencent.com/document/product/416)付费即只对CDH计费不对CDH上的实例计费。<br><li>`SPOTPAID`:表示竞价实例付费。
InstanceChargeType *string `json:"InstanceChargeType,omitempty" name:"InstanceChargeType"`
// 网卡类型例如25代表25G网卡
@ -2179,10 +2332,10 @@ type InternetAccessible struct {
// 公网出带宽上限单位Mbps。默认值0Mbps。不同机型带宽上限范围不一致具体限制详见[购买网络带宽](/document/product/213/509)。
InternetMaxBandwidthOut *int64 `json:"InternetMaxBandwidthOut,omitempty" name:"InternetMaxBandwidthOut"`
// 是否分配公网IP。取值范围<br><li>TRUE表示分配公网IP<br><li>FALSE表示不分配公网IP<br><br>当公网带宽大于0Mbps时可自由选择开通与否默认开通公网IP当公网带宽为0则不允许分配公网IP。
// 是否分配公网IP。取值范围<br><li>TRUE表示分配公网IP<br><li>FALSE表示不分配公网IP<br><br>当公网带宽大于0Mbps时可自由选择开通与否默认开通公网IP当公网带宽为0则不允许分配公网IP。该参数仅在RunInstances接口中作为入参使用。
PublicIpAssigned *bool `json:"PublicIpAssigned,omitempty" name:"PublicIpAssigned"`
// 带宽包ID。可通过[`DescribeBandwidthPackages`](https://cloud.tencent.com/document/api/215/19209)接口返回值中的`BandwidthPackageId`获取。
// 带宽包ID。可通过[`DescribeBandwidthPackages`](https://cloud.tencent.com/document/api/215/19209)接口返回值中的`BandwidthPackageId`获取。该参数仅在RunInstances接口中作为入参使用。
BandwidthPackageId *string `json:"BandwidthPackageId,omitempty" name:"BandwidthPackageId"`
}
@ -2714,6 +2867,9 @@ type Placement struct {
// 实例所属的专用宿主机ID列表。如果您有购买专用宿主机并且指定了该参数则您购买的实例就会随机的部署在这些专用宿主机上。
HostIds []*string `json:"HostIds,omitempty" name:"HostIds" list`
// 指定母机ip生产子机
HostIps []*string `json:"HostIps,omitempty" name:"HostIps" list`
}
type Price struct {
@ -2725,6 +2881,52 @@ type Price struct {
BandwidthPrice *ItemPrice `json:"BandwidthPrice,omitempty" name:"BandwidthPrice"`
}
type PurchaseReservedInstancesOfferingRequest struct {
*tchttp.BaseRequest
// 购买预留实例计费数量
InstanceCount *int64 `json:"InstanceCount,omitempty" name:"InstanceCount"`
// 预留实例计费配置ID
ReservedInstancesOfferingId *string `json:"ReservedInstancesOfferingId,omitempty" name:"ReservedInstancesOfferingId"`
// 试运行
DryRun *bool `json:"DryRun,omitempty" name:"DryRun"`
// 用于保证请求幂等性的字符串。该字符串由客户生成需保证不同请求之间唯一最大值不超过64个ASCII字符。若不指定该参数则无法保证请求的幂等性。<br>更多详细信息请参阅:如何保证幂等性
ClientToken *string `json:"ClientToken,omitempty" name:"ClientToken"`
}
func (r *PurchaseReservedInstancesOfferingRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *PurchaseReservedInstancesOfferingRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type PurchaseReservedInstancesOfferingResponse struct {
*tchttp.BaseResponse
Response *struct {
// 已购买预留实例计费ID
ReservedInstanceId *string `json:"ReservedInstanceId,omitempty" name:"ReservedInstanceId"`
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *PurchaseReservedInstancesOfferingResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *PurchaseReservedInstancesOfferingResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type RebootInstancesRequest struct {
*tchttp.BaseRequest
@ -2733,6 +2935,9 @@ type RebootInstancesRequest struct {
// 是否在正常重启失败后选择强制重启实例。取值范围:<br><li>TRUE表示在正常重启失败后进行强制重启<br><li>FALSE表示在正常重启失败后不进行强制重启<br><br>默认取值FALSE。
ForceReboot *bool `json:"ForceReboot,omitempty" name:"ForceReboot"`
// 关机类型。取值范围:<br><li>SOFT表示软关机<br><li>HARD表示硬关机<br><li>SOFT_FIRST表示优先软关机失败再执行硬关机<br><br>默认取值SOFT。
StopType *string `json:"StopType,omitempty" name:"StopType"`
}
func (r *RebootInstancesRequest) ToJsonString() string {
@ -2851,6 +3056,88 @@ func (r *RenewInstancesResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type ReservedInstances struct {
// 已购买的预留实例计费ID。形如650c138f-ae7e-4750-952a-96841d6e9fc1。
ReservedInstancesId *string `json:"ReservedInstancesId,omitempty" name:"ReservedInstancesId"`
// 预留实例计费的类型。形如S3.MEDIUM4。
// 返回项:<a href="https://cloud.tencent.com/document/product/213/11518">预留实例计费类型列表</a>
InstanceType *string `json:"InstanceType,omitempty" name:"InstanceType"`
// 预留实例计费可购买的可用区。形如ap-guangzhou-1。
// 返回项:<a href="https://cloud.tencent.com/document/product/213/6091">可用区列表</a>
Zone *string `json:"Zone,omitempty" name:"Zone"`
// 预留实例计费开始时间。形如1949-10-01 00:00:00
StartTime *string `json:"StartTime,omitempty" name:"StartTime"`
// 预留实例计费到期时间。形如1949-10-01 00:00:00
EndTime *string `json:"EndTime,omitempty" name:"EndTime"`
// 预留实例计费【有效期】即预留实例计费购买时长。形如31536000。
// 计量单位:秒。
Duration *int64 `json:"Duration,omitempty" name:"Duration"`
// 已购买的预留实例计费个数。形如10。
InstanceCount *int64 `json:"InstanceCount,omitempty" name:"InstanceCount"`
// 描述预留实例计费的平台描述即操作系统。形如linux。
// 返回项: linux 。
ProductDescription *string `json:"ProductDescription,omitempty" name:"ProductDescription"`
// 预留实例计费购买的状态。形如active
// 返回项: active (以创建) | pending (等待被创建) | retired (过期)。
State *string `json:"State,omitempty" name:"State"`
// 可购买的预留实例计费类型的结算货币使用ISO 4217标准货币代码。形如USD。
// 返回项USD美元
CurrencyCode *string `json:"CurrencyCode,omitempty" name:"CurrencyCode"`
// 预留实例计费的付款类型。形如All Upfront。
// 返回项: All Upfront (预付全部费用)。
OfferingType *string `json:"OfferingType,omitempty" name:"OfferingType"`
}
type ReservedInstancesOffering struct {
// 预留实例计费可购买的可用区。形如ap-guangzhou-1。
// 返回项:<a href="https://cloud.tencent.com/document/product/213/6091">可用区列表</a>
Zone *string `json:"Zone,omitempty" name:"Zone"`
// 可购买的预留实例计费类型的结算货币使用ISO 4217标准货币代码。
// 返回项USD美元
CurrencyCode *string `json:"CurrencyCode,omitempty" name:"CurrencyCode"`
// 预留实例计费【有效期】即预留实例计费购买时长。形如31536000。
// 计量单位:秒
Duration *int64 `json:"Duration,omitempty" name:"Duration"`
// 预留实例计费的购买价格。形如4000.0。
// 计量单位:与 currencyCode 一致,目前支持 USD美元
FixedPrice *float64 `json:"FixedPrice,omitempty" name:"FixedPrice"`
// 预留实例计费的实例类型。形如S3.MEDIUM4。
// 返回项:<a href="https://cloud.tencent.com/product/cvm/instances">预留实例计费类型列表</a>
InstanceType *string `json:"InstanceType,omitempty" name:"InstanceType"`
// 预留实例计费的付款类型。形如All Upfront。
// 返回项: All Upfront (预付全部费用)。
OfferingType *string `json:"OfferingType,omitempty" name:"OfferingType"`
// 可购买的预留实例计费配置ID。形如650c138f-ae7e-4750-952a-96841d6e9fc1。
ReservedInstancesOfferingId *string `json:"ReservedInstancesOfferingId,omitempty" name:"ReservedInstancesOfferingId"`
// 预留实例计费的平台描述即操作系统。形如linux。
// 返回项: linux 。
ProductDescription *string `json:"ProductDescription,omitempty" name:"ProductDescription"`
// 扣除预付费之后的使用价格 (按小时计费)。形如0.0。
// 目前,因为只支持 All Upfront 付款类型,所以默认为 0元/小时。
// 计量单位:元/小时,货币单位与 currencyCode 一致,目前支持 USD美元
UsagePrice *float64 `json:"UsagePrice,omitempty" name:"UsagePrice"`
}
type ResetInstanceRequest struct {
*tchttp.BaseRequest
@ -2950,7 +3237,9 @@ type ResetInstancesPasswordRequest struct {
// 一个或多个待操作的实例ID。可通过[`DescribeInstances`](https://cloud.tencent.com/document/api/213/15728) API返回值中的`InstanceId`获取。每次请求允许操作的实例数量上限是100。
InstanceIds []*string `json:"InstanceIds,omitempty" name:"InstanceIds" list`
// 实例登录密码。不同操作系统类型密码复杂度限制不一样,具体如下:<br><li>`Linux`实例密码必须8到16位至少包括两项`[a-zA-Z]、[0-9]`和`[( ) ~ ~ ! @ # $ % ^ & * - + = _ | { } [ ] : ; ' < > , . ? /]`中的符号。密码不允许以`/`符号开头。<br><li>`Windows`实例密码必须12到16位至少包括三项`[a-z][A-Z][0-9]`和`[( ) ~ ~ ! @ # $ % ^ & * - + = _ | { } [ ] : ; ' < > , . ? /]`中的符号。密码不允许以`/`符号开头。<br><li>如果实例即包含`Linux`实例又包含`Windows`实例,则密码复杂度限制按照`Windows`实例的限制。
// 实例登录密码。不同操作系统类型密码复杂度限制不一样,具体如下:
// Linux实例密码必须8-30位推荐使用12位以上密码不能以“/”开头,至少包含以下字符中的三种不同字符,字符种类:<br><li>小写字母:[a-z]<br><li>大写字母:[A-Z]<br><li>数字0-9<br><li>特殊字符: ()\`~!@#$%^&\*-+=\_|{}[]:;'<>,.?/:
// Windows实例密码必须12~30位不能以“/”开头且不包括用户名,至少包含以下字符中的三种不同字符<br><li>小写字母:[a-z]<br><li>大写字母:[A-Z]<br><li>数字: 0-9<br><li>特殊字符:()\`~!@#$%^&\*-+=\_|{}[]:;' <>,.?/:<br><li>如果实例即包含`Linux`实例又包含`Windows`实例,则密码复杂度限制按照`Windows`实例的限制。
Password *string `json:"Password,omitempty" name:"Password"`
// 待重置密码的实例操作系统用户名。不得超过64个字符。
@ -3133,6 +3422,13 @@ type RunInstancesRequest struct {
// 提供给实例使用的用户数据,需要以 base64 方式编码,支持的最大数据大小为 16KB。关于获取此参数的详细介绍请参阅[Windows](https://cloud.tencent.com/document/product/213/17526)和[Linux](https://cloud.tencent.com/document/product/213/17525)启动时运行命令。
UserData *string `json:"UserData,omitempty" name:"UserData"`
// 是否只预检此次请求。
// true发送检查请求不会创建实例。检查项包括是否填写了必需参数请求格式业务限制和云服务器库存。
// 如果检查不通过,则返回对应错误码;
// 如果检查通过则返回RequestId.
// false默认发送正常请求通过检查后直接创建实例
DryRun *bool `json:"DryRun,omitempty" name:"DryRun"`
}
func (r *RunInstancesRequest) ToJsonString() string {
@ -3422,6 +3718,43 @@ type VirtualPrivateCloud struct {
type ZoneInfo struct {
// 可用区名称例如ap-guangzhou-3
// 全网可用区名称如下:
// <li> ap-chongqing-1 </li>
// <li> ap-seoul-1 </li>
// <li> ap-chengdu-1 </li>
// <li> ap-chengdu-2 </li>
// <li> ap-hongkong-1 </li>
// <li> ap-hongkong-2 </li>
// <li> ap-shenzhen-fsi-1 </li>
// <li> ap-shenzhen-fsi-2 </li>
// <li> ap-shenzhen-fsi-3 </li>
// <li> ap-guangzhou-1售罄</li>
// <li> ap-guangzhou-2售罄</li>
// <li> ap-guangzhou-3 </li>
// <li> ap-guangzhou-4 </li>
// <li> ap-tokyo-1 </li>
// <li> ap-singapore-1 </li>
// <li> ap-shanghai-fsi-1 </li>
// <li> ap-shanghai-fsi-2 </li>
// <li> ap-shanghai-fsi-3 </li>
// <li> ap-bangkok-1 </li>
// <li> ap-shanghai-1售罄 </li>
// <li> ap-shanghai-2 </li>
// <li> ap-shanghai-3 </li>
// <li> ap-shanghai-4 </li>
// <li> ap-mumbai-1 </li>
// <li> ap-mumbai-2 </li>
// <li> eu-moscow-1 </li>
// <li> ap-beijing-1 </li>
// <li> ap-beijing-2 </li>
// <li> ap-beijing-3 </li>
// <li> ap-beijing-4 </li>
// <li> na-siliconvalley-1 </li>
// <li> na-siliconvalley-2 </li>
// <li> eu-frankfurt-1 </li>
// <li> na-toronto-1 </li>
// <li> na-ashburn-1 </li>
// <li> na-ashburn-2 </li>
Zone *string `json:"Zone,omitempty" name:"Zone"`
// 可用区描述,例如,广州三区

View File

@ -137,8 +137,8 @@ func NewAllocateAddressesResponse() (response *AllocateAddressesResponse) {
// 本接口 (AllocateAddresses) 用于申请一个或多个[弹性公网IP](https://cloud.tencent.com/document/product/213/1941)(简称 EIP
// * EIP 是专为动态云计算设计的静态 IP 地址。借助 EIP您可以快速将 EIP 重新映射到您的另一个实例上,从而屏蔽实例故障。
// * 您的 EIP 与腾讯云账户相关联,而不是与某个实例相关联。在您选择显式释放该地址,或欠费超过七天之前,它会一直与您的腾讯云账户保持关联。
// * 平台对用户每地域能申请的 EIP 最大配额有所限制,可参见 [EIP 产品简介](https://cloud.tencent.com/document/product/213/5733),上述配额可通过 DescribeAddressQuota 接口获取。
// * 您的 EIP 与腾讯云账户相关联,而不是与某个实例相关联。在您选择显式释放该地址,或欠费超过24小时之前,它会一直与您的腾讯云账户保持关联。
// * 一个腾讯云账户在每个地域能申请的 EIP 最大配额有所限制,可参见 [EIP 产品简介](https://cloud.tencent.com/document/product/213/5733),上述配额可通过 DescribeAddressQuota 接口获取。
func (c *Client) AllocateAddresses(request *AllocateAddressesRequest) (response *AllocateAddressesResponse, err error) {
if request == nil {
request = NewAllocateAddressesRequest()
@ -291,6 +291,31 @@ func (c *Client) AssociateAddress(request *AssociateAddressRequest) (response *A
return
}
func NewAssociateNatGatewayAddressRequest() (request *AssociateNatGatewayAddressRequest) {
request = &AssociateNatGatewayAddressRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("vpc", APIVersion, "AssociateNatGatewayAddress")
return
}
func NewAssociateNatGatewayAddressResponse() (response *AssociateNatGatewayAddressResponse) {
response = &AssociateNatGatewayAddressResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口(AssociateNatGatewayAddress)用于NAT网关绑定弹性IPEIP
func (c *Client) AssociateNatGatewayAddress(request *AssociateNatGatewayAddressRequest) (response *AssociateNatGatewayAddressResponse, err error) {
if request == nil {
request = NewAssociateNatGatewayAddressRequest()
}
response = NewAssociateNatGatewayAddressResponse()
err = c.Send(request, response)
return
}
func NewAttachCcnInstancesRequest() (request *AttachCcnInstancesRequest) {
request = &AttachCcnInstancesRequest{
BaseRequest: &tchttp.BaseRequest{},
@ -658,6 +683,56 @@ func (c *Client) CreateIp6Translators(request *CreateIp6TranslatorsRequest) (res
return
}
func NewCreateNatGatewayRequest() (request *CreateNatGatewayRequest) {
request = &CreateNatGatewayRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("vpc", APIVersion, "CreateNatGateway")
return
}
func NewCreateNatGatewayResponse() (response *CreateNatGatewayResponse) {
response = &CreateNatGatewayResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口(CreateNatGateway)用于创建NAT网关。
func (c *Client) CreateNatGateway(request *CreateNatGatewayRequest) (response *CreateNatGatewayResponse, err error) {
if request == nil {
request = NewCreateNatGatewayRequest()
}
response = NewCreateNatGatewayResponse()
err = c.Send(request, response)
return
}
func NewCreateNatGatewayDestinationIpPortTranslationNatRuleRequest() (request *CreateNatGatewayDestinationIpPortTranslationNatRuleRequest) {
request = &CreateNatGatewayDestinationIpPortTranslationNatRuleRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("vpc", APIVersion, "CreateNatGatewayDestinationIpPortTranslationNatRule")
return
}
func NewCreateNatGatewayDestinationIpPortTranslationNatRuleResponse() (response *CreateNatGatewayDestinationIpPortTranslationNatRuleResponse) {
response = &CreateNatGatewayDestinationIpPortTranslationNatRuleResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口(CreateNatGatewayDestinationIpPortTranslationNatRule)用于创建NAT网关端口转发规则。
func (c *Client) CreateNatGatewayDestinationIpPortTranslationNatRule(request *CreateNatGatewayDestinationIpPortTranslationNatRuleRequest) (response *CreateNatGatewayDestinationIpPortTranslationNatRuleResponse, err error) {
if request == nil {
request = NewCreateNatGatewayDestinationIpPortTranslationNatRuleRequest()
}
response = NewCreateNatGatewayDestinationIpPortTranslationNatRuleResponse()
err = c.Send(request, response)
return
}
func NewCreateNetworkInterfaceRequest() (request *CreateNetworkInterfaceRequest) {
request = &CreateNetworkInterfaceRequest{
BaseRequest: &tchttp.BaseRequest{},
@ -1244,6 +1319,57 @@ func (c *Client) DeleteIp6Translators(request *DeleteIp6TranslatorsRequest) (res
return
}
func NewDeleteNatGatewayRequest() (request *DeleteNatGatewayRequest) {
request = &DeleteNatGatewayRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("vpc", APIVersion, "DeleteNatGateway")
return
}
func NewDeleteNatGatewayResponse() (response *DeleteNatGatewayResponse) {
response = &DeleteNatGatewayResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口DeleteNatGateway用于删除NAT网关。
// 删除 NAT 网关后,系统会自动删除路由表中包含此 NAT 网关的路由项同时也会解绑弹性公网IPEIP
func (c *Client) DeleteNatGateway(request *DeleteNatGatewayRequest) (response *DeleteNatGatewayResponse, err error) {
if request == nil {
request = NewDeleteNatGatewayRequest()
}
response = NewDeleteNatGatewayResponse()
err = c.Send(request, response)
return
}
func NewDeleteNatGatewayDestinationIpPortTranslationNatRuleRequest() (request *DeleteNatGatewayDestinationIpPortTranslationNatRuleRequest) {
request = &DeleteNatGatewayDestinationIpPortTranslationNatRuleRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("vpc", APIVersion, "DeleteNatGatewayDestinationIpPortTranslationNatRule")
return
}
func NewDeleteNatGatewayDestinationIpPortTranslationNatRuleResponse() (response *DeleteNatGatewayDestinationIpPortTranslationNatRuleResponse) {
response = &DeleteNatGatewayDestinationIpPortTranslationNatRuleResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口DeleteNatGatewayDestinationIpPortTranslationNatRule用于删除NAT网关端口转发规则。
func (c *Client) DeleteNatGatewayDestinationIpPortTranslationNatRule(request *DeleteNatGatewayDestinationIpPortTranslationNatRuleRequest) (response *DeleteNatGatewayDestinationIpPortTranslationNatRuleResponse, err error) {
if request == nil {
request = NewDeleteNatGatewayDestinationIpPortTranslationNatRuleRequest()
}
response = NewDeleteNatGatewayDestinationIpPortTranslationNatRuleResponse()
err = c.Send(request, response)
return
}
func NewDeleteNetworkInterfaceRequest() (request *DeleteNetworkInterfaceRequest) {
request = &DeleteNetworkInterfaceRequest{
BaseRequest: &tchttp.BaseRequest{},
@ -2082,6 +2208,81 @@ func (c *Client) DescribeIp6Translators(request *DescribeIp6TranslatorsRequest)
return
}
func NewDescribeNatGatewayDestinationIpPortTranslationNatRulesRequest() (request *DescribeNatGatewayDestinationIpPortTranslationNatRulesRequest) {
request = &DescribeNatGatewayDestinationIpPortTranslationNatRulesRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("vpc", APIVersion, "DescribeNatGatewayDestinationIpPortTranslationNatRules")
return
}
func NewDescribeNatGatewayDestinationIpPortTranslationNatRulesResponse() (response *DescribeNatGatewayDestinationIpPortTranslationNatRulesResponse) {
response = &DescribeNatGatewayDestinationIpPortTranslationNatRulesResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口DescribeNatGatewayDestinationIpPortTranslationNatRules用于查询NAT网关端口转发规则对象数组。
func (c *Client) DescribeNatGatewayDestinationIpPortTranslationNatRules(request *DescribeNatGatewayDestinationIpPortTranslationNatRulesRequest) (response *DescribeNatGatewayDestinationIpPortTranslationNatRulesResponse, err error) {
if request == nil {
request = NewDescribeNatGatewayDestinationIpPortTranslationNatRulesRequest()
}
response = NewDescribeNatGatewayDestinationIpPortTranslationNatRulesResponse()
err = c.Send(request, response)
return
}
func NewDescribeNatGatewaysRequest() (request *DescribeNatGatewaysRequest) {
request = &DescribeNatGatewaysRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("vpc", APIVersion, "DescribeNatGateways")
return
}
func NewDescribeNatGatewaysResponse() (response *DescribeNatGatewaysResponse) {
response = &DescribeNatGatewaysResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口DescribeNatGateways用于查询 NAT 网关。
func (c *Client) DescribeNatGateways(request *DescribeNatGatewaysRequest) (response *DescribeNatGatewaysResponse, err error) {
if request == nil {
request = NewDescribeNatGatewaysRequest()
}
response = NewDescribeNatGatewaysResponse()
err = c.Send(request, response)
return
}
func NewDescribeNetworkInterfaceLimitRequest() (request *DescribeNetworkInterfaceLimitRequest) {
request = &DescribeNetworkInterfaceLimitRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("vpc", APIVersion, "DescribeNetworkInterfaceLimit")
return
}
func NewDescribeNetworkInterfaceLimitResponse() (response *DescribeNetworkInterfaceLimitResponse) {
response = &DescribeNetworkInterfaceLimitResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口DescribeNetworkInterfaceLimit根据CVM实例ID查询弹性网卡配额返回该CVM实例能绑定的弹性网卡配额以及每个弹性网卡可以分配的ip配额
func (c *Client) DescribeNetworkInterfaceLimit(request *DescribeNetworkInterfaceLimitRequest) (response *DescribeNetworkInterfaceLimitResponse, err error) {
if request == nil {
request = NewDescribeNetworkInterfaceLimitRequest()
}
response = NewDescribeNetworkInterfaceLimitResponse()
err = c.Send(request, response)
return
}
func NewDescribeNetworkInterfacesRequest() (request *DescribeNetworkInterfacesRequest) {
request = &DescribeNetworkInterfacesRequest{
BaseRequest: &tchttp.BaseRequest{},
@ -2307,6 +2508,31 @@ func (c *Client) DescribeSubnets(request *DescribeSubnetsRequest) (response *Des
return
}
func NewDescribeTaskResultRequest() (request *DescribeTaskResultRequest) {
request = &DescribeTaskResultRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("vpc", APIVersion, "DescribeTaskResult")
return
}
func NewDescribeTaskResultResponse() (response *DescribeTaskResultResponse) {
response = &DescribeTaskResultResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 查询EIP异步任务执行结果
func (c *Client) DescribeTaskResult(request *DescribeTaskResultRequest) (response *DescribeTaskResultResponse, err error) {
if request == nil {
request = NewDescribeTaskResultRequest()
}
response = NewDescribeTaskResultResponse()
err = c.Send(request, response)
return
}
func NewDescribeVpcIpv6AddressesRequest() (request *DescribeVpcIpv6AddressesRequest) {
request = &DescribeVpcIpv6AddressesRequest{
BaseRequest: &tchttp.BaseRequest{},
@ -2589,6 +2815,31 @@ func (c *Client) DisassociateAddress(request *DisassociateAddressRequest) (respo
return
}
func NewDisassociateNatGatewayAddressRequest() (request *DisassociateNatGatewayAddressRequest) {
request = &DisassociateNatGatewayAddressRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("vpc", APIVersion, "DisassociateNatGatewayAddress")
return
}
func NewDisassociateNatGatewayAddressResponse() (response *DisassociateNatGatewayAddressResponse) {
response = &DisassociateNatGatewayAddressResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口DisassociateNatGatewayAddress用于NAT网关解绑弹性IP。
func (c *Client) DisassociateNatGatewayAddress(request *DisassociateNatGatewayAddressRequest) (response *DisassociateNatGatewayAddressResponse, err error) {
if request == nil {
request = NewDisassociateNatGatewayAddressRequest()
}
response = NewDisassociateNatGatewayAddressResponse()
err = c.Send(request, response)
return
}
func NewDownloadCustomerGatewayConfigurationRequest() (request *DownloadCustomerGatewayConfigurationRequest) {
request = &DownloadCustomerGatewayConfigurationRequest{
BaseRequest: &tchttp.BaseRequest{},
@ -3171,6 +3422,56 @@ func (c *Client) ModifyIpv6AddressesAttribute(request *ModifyIpv6AddressesAttrib
return
}
func NewModifyNatGatewayAttributeRequest() (request *ModifyNatGatewayAttributeRequest) {
request = &ModifyNatGatewayAttributeRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("vpc", APIVersion, "ModifyNatGatewayAttribute")
return
}
func NewModifyNatGatewayAttributeResponse() (response *ModifyNatGatewayAttributeResponse) {
response = &ModifyNatGatewayAttributeResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口ModifyNatGatewayAttribute用于修改NAT网关的属性。
func (c *Client) ModifyNatGatewayAttribute(request *ModifyNatGatewayAttributeRequest) (response *ModifyNatGatewayAttributeResponse, err error) {
if request == nil {
request = NewModifyNatGatewayAttributeRequest()
}
response = NewModifyNatGatewayAttributeResponse()
err = c.Send(request, response)
return
}
func NewModifyNatGatewayDestinationIpPortTranslationNatRuleRequest() (request *ModifyNatGatewayDestinationIpPortTranslationNatRuleRequest) {
request = &ModifyNatGatewayDestinationIpPortTranslationNatRuleRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("vpc", APIVersion, "ModifyNatGatewayDestinationIpPortTranslationNatRule")
return
}
func NewModifyNatGatewayDestinationIpPortTranslationNatRuleResponse() (response *ModifyNatGatewayDestinationIpPortTranslationNatRuleResponse) {
response = &ModifyNatGatewayDestinationIpPortTranslationNatRuleResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口ModifyNatGatewayDestinationIpPortTranslationNatRule用于修改NAT网关端口转发规则。
func (c *Client) ModifyNatGatewayDestinationIpPortTranslationNatRule(request *ModifyNatGatewayDestinationIpPortTranslationNatRuleRequest) (response *ModifyNatGatewayDestinationIpPortTranslationNatRuleResponse, err error) {
if request == nil {
request = NewModifyNatGatewayDestinationIpPortTranslationNatRuleRequest()
}
response = NewModifyNatGatewayDestinationIpPortTranslationNatRuleResponse()
err = c.Send(request, response)
return
}
func NewModifyNetworkInterfaceAttributeRequest() (request *ModifyNetworkInterfaceAttributeRequest) {
request = &ModifyNetworkInterfaceAttributeRequest{
BaseRequest: &tchttp.BaseRequest{},
@ -3710,6 +4011,31 @@ func (c *Client) ResetAttachCcnInstances(request *ResetAttachCcnInstancesRequest
return
}
func NewResetNatGatewayConnectionRequest() (request *ResetNatGatewayConnectionRequest) {
request = &ResetNatGatewayConnectionRequest{
BaseRequest: &tchttp.BaseRequest{},
}
request.Init().WithApiInfo("vpc", APIVersion, "ResetNatGatewayConnection")
return
}
func NewResetNatGatewayConnectionResponse() (response *ResetNatGatewayConnectionResponse) {
response = &ResetNatGatewayConnectionResponse{
BaseResponse: &tchttp.BaseResponse{},
}
return
}
// 本接口ResetNatGatewayConnection用来NAT网关并发连接上限。
func (c *Client) ResetNatGatewayConnection(request *ResetNatGatewayConnectionRequest) (response *ResetNatGatewayConnectionResponse, err error) {
if request == nil {
request = NewResetNatGatewayConnectionRequest()
}
response = NewResetNatGatewayConnectionResponse()
err = c.Send(request, response)
return
}
func NewResetRoutesRequest() (request *ResetRoutesRequest) {
request = &ResetRoutesRequest{
BaseRequest: &tchttp.BaseRequest{},

View File

@ -160,7 +160,7 @@ type Address struct {
// `EIP`名称。
AddressName *string `json:"AddressName,omitempty" name:"AddressName"`
// `EIP`状态
// `EIP`状态,包含'CREATING'(创建中),'BINDING'(绑定中),'BIND'(已绑定),'UNBINDING'(解绑中),'UNBIND'(已解绑),'OFFLINING'(释放中),'BIND_ENI'(绑定悬空弹性网卡)
AddressStatus *string `json:"AddressStatus,omitempty" name:"AddressStatus"`
// 外网IP地址
@ -236,8 +236,41 @@ type AddressTemplateSpecification struct {
type AllocateAddressesRequest struct {
*tchttp.BaseRequest
// 申请 EIP 数量,默认值为1。
// EIP数量。默认值1。
AddressCount *int64 `json:"AddressCount,omitempty" name:"AddressCount"`
// EIP线路类型。默认值BGP。
// <ul style="margin:0"><li>已开通静态单线IP白名单的用户可选值<ul><li>CMCC中国移动</li>
// <li>CTCC中国电信</li>
// <li>CUCC中国联通</li></ul>注意仅部分地域支持静态单线IP。</li></ul>
InternetServiceProvider *string `json:"InternetServiceProvider,omitempty" name:"InternetServiceProvider"`
// EIP计费方式。
// <ul style="margin:0"><li>已开通带宽上移白名单的用户,可选值:<ul><li>BANDWIDTH_PACKAGE[共享带宽包](https://cloud.tencent.com/document/product/684/15255)付费(需额外开通共享带宽包白名单)</li>
// <li>BANDWIDTH_POSTPAID_BY_HOUR带宽按小时后付费</li>
// <li>TRAFFIC_POSTPAID_BY_HOUR流量按小时后付费</li></ul>默认值TRAFFIC_POSTPAID_BY_HOUR。</li>
// <li>未开通带宽上移白名单的用户EIP计费方式与其绑定的实例的计费方式一致无需传递此参数。</li></ul>
InternetChargeType *string `json:"InternetChargeType,omitempty" name:"InternetChargeType"`
// EIP出带宽上限单位Mbps。
// <ul style="margin:0"><li>已开通带宽上移白名单的用户可选值范围取决于EIP计费方式<ul><li>BANDWIDTH_PACKAGE1 Mbps 至 1000 Mbps</li>
// <li>BANDWIDTH_POSTPAID_BY_HOUR1 Mbps 至 100 Mbps</li>
// <li>TRAFFIC_POSTPAID_BY_HOUR1 Mbps 至 100 Mbps</li></ul>默认值1 Mbps。</li>
// <li>未开通带宽上移白名单的用户EIP出带宽上限取决于与其绑定的实例的公网出带宽上限无需传递此参数。</li></ul>
InternetMaxBandwidthOut *int64 `json:"InternetMaxBandwidthOut,omitempty" name:"InternetMaxBandwidthOut"`
// EIP类型。默认值EIP。
// <ul style="margin:0"><li>已开通Anycast公网加速白名单的用户可选值<ul><li>AnycastEIP加速IP可参见 [Anycast 公网加速](https://cloud.tencent.com/document/product/644)</li></ul>注意仅部分地域支持加速IP。</li></ul>
AddressType *string `json:"AddressType,omitempty" name:"AddressType"`
// Anycast发布域。
// <ul style="margin:0"><li>已开通Anycast公网加速白名单的用户可选值<ul><li>ANYCAST_ZONE_GLOBAL全球发布域需要额外开通Anycast全球加速白名单</li><li>ANYCAST_ZONE_OVERSEAS境外发布域</li></ul>默认值ANYCAST_ZONE_OVERSEAS。</li></ul>
AnycastZone *string `json:"AnycastZone,omitempty" name:"AnycastZone"`
// AnycastEIP是否用于绑定负载均衡。
// <ul style="margin:0"><li>已开通Anycast公网加速白名单的用户可选值<ul><li>TRUEAnycastEIP可绑定对象为负载均衡</li>
// <li>FALSEAnycastEIP可绑定对象为云服务器、NAT网关、高可用虚拟IP等</li></ul>默认值FALSE。</li></ul>
ApplicableForCLB *bool `json:"ApplicableForCLB,omitempty" name:"ApplicableForCLB"`
}
func (r *AllocateAddressesRequest) ToJsonString() string {
@ -256,6 +289,9 @@ type AllocateAddressesResponse struct {
// 申请到的 EIP 的唯一 ID 列表。
AddressSet []*string `json:"AddressSet,omitempty" name:"AddressSet" list`
// 异步任务TaskId。可以使用[DescribeTaskResult](https://cloud.tencent.com/document/api/215/36271)接口查询任务状态。
TaskId *string `json:"TaskId,omitempty" name:"TaskId"`
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
@ -399,7 +435,7 @@ type AssignPrivateIpAddressesRequest struct {
// 指定的内网IP信息单次最多指定10个。
PrivateIpAddresses []*PrivateIpAddressSpecification `json:"PrivateIpAddresses,omitempty" name:"PrivateIpAddresses" list`
// 新申请的内网IP地址个数内网IP地址个数总和不能超过配数。
// 新申请的内网IP地址个数内网IP地址个数总和不能超过配,详见<a href="/document/product/576/18527">弹性网卡使用限制</a>
SecondaryPrivateIpAddressCount *uint64 `json:"SecondaryPrivateIpAddressCount,omitempty" name:"SecondaryPrivateIpAddressCount"`
}
@ -433,6 +469,22 @@ func (r *AssignPrivateIpAddressesResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type AssistantCidr struct {
// `VPC`实例`ID`。形如:`vpc-6v2ht8q5`
VpcId *string `json:"VpcId,omitempty" name:"VpcId"`
// 辅助CIDR。形如`172.16.0.0/16`
CidrBlock *string `json:"CidrBlock,omitempty" name:"CidrBlock"`
// 辅助CIDR类型0普通辅助CIDR1容器辅助CIDR默认都是0。
AssistantType *int64 `json:"AssistantType,omitempty" name:"AssistantType"`
// 辅助CIDR拆分的子网。
// 注意:此字段可能返回 null表示取不到有效值。
SubnetSet []*Subnet `json:"SubnetSet,omitempty" name:"SubnetSet" list`
}
type AssociateAddressRequest struct {
*tchttp.BaseRequest
@ -462,6 +514,9 @@ type AssociateAddressResponse struct {
*tchttp.BaseResponse
Response *struct {
// 异步任务TaskId。可以使用[DescribeTaskResult](https://cloud.tencent.com/document/api/215/36271)接口查询任务状态。
TaskId *string `json:"TaskId,omitempty" name:"TaskId"`
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
@ -476,6 +531,49 @@ func (r *AssociateAddressResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type AssociateNatGatewayAddressRequest struct {
*tchttp.BaseRequest
// NAT网关的ID形如`nat-df45454`。
NatGatewayId *string `json:"NatGatewayId,omitempty" name:"NatGatewayId"`
// 需要申请的弹性IP个数系统会按您的要求生产N个弹性IP, 其中AddressCount和PublicAddresses至少传递一个。
AddressCount *uint64 `json:"AddressCount,omitempty" name:"AddressCount"`
// 绑定NAT网关的弹性IP数组其中AddressCount和PublicAddresses至少传递一个。。
PublicIpAddresses []*string `json:"PublicIpAddresses,omitempty" name:"PublicIpAddresses" list`
// 弹性IP可以区自动分配弹性IP时传递。
Zone *string `json:"Zone,omitempty" name:"Zone"`
}
func (r *AssociateNatGatewayAddressRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *AssociateNatGatewayAddressRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type AssociateNatGatewayAddressResponse struct {
*tchttp.BaseResponse
Response *struct {
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *AssociateNatGatewayAddressResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *AssociateNatGatewayAddressResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type AttachCcnInstancesRequest struct {
*tchttp.BaseRequest
@ -910,6 +1008,12 @@ type CreateCcnRequest struct {
// CCN服务质量'PT':白金,'AU':金,'AG'默认为AU
QosLevel *string `json:"QosLevel,omitempty" name:"QosLevel"`
// 计费模式PREPAID表示预付费即包年包月POSTPAID表示后付费即按量计费。默认POSTPAID。
InstanceChargeType *string `json:"InstanceChargeType,omitempty" name:"InstanceChargeType"`
// 限速类型OUTER_REGION_LIMIT表示地域出口限速INTER_REGION_LIMIT为地域间限速默认为OUTER_REGION_LIMIT
BandwidthLimitType *string `json:"BandwidthLimitType,omitempty" name:"BandwidthLimitType"`
}
func (r *CreateCcnRequest) ToJsonString() string {
@ -1254,6 +1358,101 @@ func (r *CreateIp6TranslatorsResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type CreateNatGatewayDestinationIpPortTranslationNatRuleRequest struct {
*tchttp.BaseRequest
// NAT网关的ID形如`nat-df45454`。
NatGatewayId *string `json:"NatGatewayId,omitempty" name:"NatGatewayId"`
// NAT网关的端口转换规则。
DestinationIpPortTranslationNatRules []*DestinationIpPortTranslationNatRule `json:"DestinationIpPortTranslationNatRules,omitempty" name:"DestinationIpPortTranslationNatRules" list`
}
func (r *CreateNatGatewayDestinationIpPortTranslationNatRuleRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *CreateNatGatewayDestinationIpPortTranslationNatRuleRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type CreateNatGatewayDestinationIpPortTranslationNatRuleResponse struct {
*tchttp.BaseResponse
Response *struct {
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *CreateNatGatewayDestinationIpPortTranslationNatRuleResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *CreateNatGatewayDestinationIpPortTranslationNatRuleResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type CreateNatGatewayRequest struct {
*tchttp.BaseRequest
// NAT网关名称
NatGatewayName *string `json:"NatGatewayName,omitempty" name:"NatGatewayName"`
// VPC实例ID。可通过DescribeVpcs接口返回值中的VpcId获取。
VpcId *string `json:"VpcId,omitempty" name:"VpcId"`
// NAT网关最大外网出带宽(单位:Mbps),支持的参数值:`20, 50, 100, 200, 500, 1000, 2000, 5000`,默认: `100Mbps`。
InternetMaxBandwidthOut *uint64 `json:"InternetMaxBandwidthOut,omitempty" name:"InternetMaxBandwidthOut"`
// NAT网关并发连接上限支持参数值`1000000、3000000、10000000`,默认值为`100000`。
MaxConcurrentConnection *uint64 `json:"MaxConcurrentConnection,omitempty" name:"MaxConcurrentConnection"`
// 需要申请的弹性IP个数系统会按您的要求生产N个弹性IP其中AddressCount和PublicAddresses至少传递一个。
AddressCount *uint64 `json:"AddressCount,omitempty" name:"AddressCount"`
// 绑定NAT网关的弹性IP数组其中AddressCount和PublicAddresses至少传递一个。
PublicIpAddresses []*string `json:"PublicIpAddresses,omitempty" name:"PublicIpAddresses" list`
// 可用区,形如:`ap-guangzhou-1`。
Zone *string `json:"Zone,omitempty" name:"Zone"`
}
func (r *CreateNatGatewayRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *CreateNatGatewayRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type CreateNatGatewayResponse struct {
*tchttp.BaseResponse
Response *struct {
// NAT网关对象数组。
NatGatewaySet []*NatGateway `json:"NatGatewaySet,omitempty" name:"NatGatewaySet" list`
// 符合条件的 NAT网关对象数量。
TotalCount *uint64 `json:"TotalCount,omitempty" name:"TotalCount"`
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *CreateNatGatewayResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *CreateNatGatewayResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type CreateNetworkInterfaceRequest struct {
*tchttp.BaseRequest
@ -1644,7 +1843,7 @@ type CreateVpcRequest struct {
// vpc名称最大长度不能超过60个字节。
VpcName *string `json:"VpcName,omitempty" name:"VpcName"`
// vpc的cidr只能为10.0.0.0/16172.16.0.0/12192.168.0.0/16这三个内网网段内。
// vpc的cidr只能为10.0.0.0/16172.16.0.0/16192.168.0.0/16这三个内网网段内。
CidrBlock *string `json:"CidrBlock,omitempty" name:"CidrBlock"`
// 是否开启组播。true: 开启, false: 不开启。
@ -2179,6 +2378,77 @@ func (r *DeleteIp6TranslatorsResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DeleteNatGatewayDestinationIpPortTranslationNatRuleRequest struct {
*tchttp.BaseRequest
// NAT网关的ID形如`nat-df45454`。
NatGatewayId *string `json:"NatGatewayId,omitempty" name:"NatGatewayId"`
// NAT网关的端口转换规则。
DestinationIpPortTranslationNatRules []*DestinationIpPortTranslationNatRule `json:"DestinationIpPortTranslationNatRules,omitempty" name:"DestinationIpPortTranslationNatRules" list`
}
func (r *DeleteNatGatewayDestinationIpPortTranslationNatRuleRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DeleteNatGatewayDestinationIpPortTranslationNatRuleRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DeleteNatGatewayDestinationIpPortTranslationNatRuleResponse struct {
*tchttp.BaseResponse
Response *struct {
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *DeleteNatGatewayDestinationIpPortTranslationNatRuleResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DeleteNatGatewayDestinationIpPortTranslationNatRuleResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DeleteNatGatewayRequest struct {
*tchttp.BaseRequest
// NAT网关的ID形如`nat-df45454`。
NatGatewayId *string `json:"NatGatewayId,omitempty" name:"NatGatewayId"`
}
func (r *DeleteNatGatewayRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DeleteNatGatewayRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DeleteNatGatewayResponse struct {
*tchttp.BaseResponse
Response *struct {
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *DeleteNatGatewayResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DeleteNatGatewayResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DeleteNetworkInterfaceRequest struct {
*tchttp.BaseRequest
@ -2736,7 +3006,7 @@ type DescribeAddressesRequest struct {
// <li> address-id - String - 是否必填:否 - (过滤条件)按照 EIP 的唯一 ID 过滤。EIP 唯一 ID 形如eip-11112222。</li>
// <li> address-name - String - 是否必填:否 - (过滤条件)按照 EIP 名称过滤。不支持模糊过滤。</li>
// <li> address-ip - String - 是否必填:否 - (过滤条件)按照 EIP 的 IP 地址过滤。</li>
// <li> address-status - String - 是否必填:否 - (过滤条件)按照 EIP 的状态过滤。取值范围:[详见EIP状态列表](https://cloud.tencent.com/document/api/213/9452#eip_state)。</li>
// <li> address-status - String - 是否必填:否 - (过滤条件)按照 EIP 的状态过滤。状态包含:'CREATING''BINDING''BIND''UNBINDING''UNBIND''OFFLINING''BIND_ENI'。</li>
// <li> instance-id - String - 是否必填:否 - (过滤条件)按照 EIP 绑定的实例 ID 过滤。实例 ID 形如ins-11112222。</li>
// <li> private-ip-address - String - 是否必填:否 - (过滤条件)按照 EIP 绑定的内网 IP 过滤。</li>
// <li> network-interface-id - String - 是否必填:否 - (过滤条件)按照 EIP 绑定的弹性网卡 ID 过滤。弹性网卡 ID 形如eni-11112222。</li>
@ -3037,6 +3307,8 @@ type DescribeCcnsRequest struct {
// <li>ccn-name - String - 过滤条件CCN名称。</li>
// <li>ccn-description - String - 过滤条件CCN描述。</li>
// <li>state - String - (过滤条件)实例状态, 'ISOLATED': 隔离中(欠费停服),'AVAILABLE':运行中。</li>
// <li>tag-key - String -是否必填:否- (过滤条件)按照标签键进行过滤。</li>
// <li>tag:tag-key - String - 是否必填:否 - (过滤条件)按照标签键值对进行过滤。 tag-key使用具体的标签键进行替换。使用请参考示例查询绑定了标签的CCN列表。</li>
Filters []*Filter `json:"Filters,omitempty" name:"Filters" list`
// 偏移量
@ -3648,6 +3920,155 @@ func (r *DescribeIp6TranslatorsResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeNatGatewayDestinationIpPortTranslationNatRulesRequest struct {
*tchttp.BaseRequest
// NAT网关ID。
NatGatewayIds []*string `json:"NatGatewayIds,omitempty" name:"NatGatewayIds" list`
// 过滤条件:
// 参数不支持同时指定NatGatewayIds和Filters。
// <li> nat-gateway-idNAT网关的ID如`nat-0yi4hekt`</li>
// <li> vpc-id私有网络VPC的ID如`vpc-0yi4hekt`</li>
// <li> public-ip-address 弹性IP如`139.199.232.238`。</li>
// <li>public-port 公网端口。</li>
// <li>private-ip-address 内网IP如`10.0.0.1`。</li>
// <li>private-port 内网端口。</li>
// <li>description规则描述。</li>
Filters []*Filter `json:"Filters,omitempty" name:"Filters" list`
// 偏移量默认为0。
Offset *uint64 `json:"Offset,omitempty" name:"Offset"`
// 返回数量默认为20最大值为100。
Limit *uint64 `json:"Limit,omitempty" name:"Limit"`
}
func (r *DescribeNatGatewayDestinationIpPortTranslationNatRulesRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DescribeNatGatewayDestinationIpPortTranslationNatRulesRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeNatGatewayDestinationIpPortTranslationNatRulesResponse struct {
*tchttp.BaseResponse
Response *struct {
// NAT网关端口转发规则对象数组。
NatGatewayDestinationIpPortTranslationNatRuleSet []*NatGatewayDestinationIpPortTranslationNatRule `json:"NatGatewayDestinationIpPortTranslationNatRuleSet,omitempty" name:"NatGatewayDestinationIpPortTranslationNatRuleSet" list`
// 符合条件的NAT网关端口转发规则对象数目。
TotalCount *uint64 `json:"TotalCount,omitempty" name:"TotalCount"`
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *DescribeNatGatewayDestinationIpPortTranslationNatRulesResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DescribeNatGatewayDestinationIpPortTranslationNatRulesResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeNatGatewaysRequest struct {
*tchttp.BaseRequest
// NAT网关统一 ID形如`nat-123xx454`。
NatGatewayIds []*string `json:"NatGatewayIds,omitempty" name:"NatGatewayIds" list`
// 过滤条件参数不支持同时指定NatGatewayIds和Filters。
// <li>nat-gateway-id - String - 过滤条件协议端口模板实例ID形如`nat-123xx454`。</li>
// <li>vpc-id - String - (过滤条件)私有网络 唯一ID形如`vpc-123xx454`。</li>
// <li>nat-gateway-name - String - 过滤条件协议端口模板实例ID形如`test_nat`。</li>
Filters []*Filter `json:"Filters,omitempty" name:"Filters" list`
// 偏移量默认为0。
Offset *uint64 `json:"Offset,omitempty" name:"Offset"`
// 返回数量默认为20最大值为100。
Limit *uint64 `json:"Limit,omitempty" name:"Limit"`
}
func (r *DescribeNatGatewaysRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DescribeNatGatewaysRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeNatGatewaysResponse struct {
*tchttp.BaseResponse
Response *struct {
// NAT网关对象数组。
NatGatewaySet []*NatGateway `json:"NatGatewaySet,omitempty" name:"NatGatewaySet" list`
// 符合条件的NAT网关对象个数。
TotalCount *uint64 `json:"TotalCount,omitempty" name:"TotalCount"`
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *DescribeNatGatewaysResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DescribeNatGatewaysResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeNetworkInterfaceLimitRequest struct {
*tchttp.BaseRequest
// 要查询的CVM实例ID
InstanceId *string `json:"InstanceId,omitempty" name:"InstanceId"`
}
func (r *DescribeNetworkInterfaceLimitRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DescribeNetworkInterfaceLimitRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeNetworkInterfaceLimitResponse struct {
*tchttp.BaseResponse
Response *struct {
// 弹性网卡配额
EniQuantity *int64 `json:"EniQuantity,omitempty" name:"EniQuantity"`
// 每个弹性网卡可以分配的ip配额
EniPrivateIpAddressQuantity *int64 `json:"EniPrivateIpAddressQuantity,omitempty" name:"EniPrivateIpAddressQuantity"`
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *DescribeNetworkInterfaceLimitResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DescribeNetworkInterfaceLimitResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeNetworkInterfacesRequest struct {
*tchttp.BaseRequest
@ -3662,6 +4083,9 @@ type DescribeNetworkInterfacesRequest struct {
// <li>groups.security-group-id - String - 过滤条件绑定的安全组实例ID例如sg-f9ekbxeq。</li>
// <li>network-interface-name - String - (过滤条件)网卡实例名称。</li>
// <li>network-interface-description - String - (过滤条件)网卡实例描述。</li>
// <li>address-ip - String - 过滤条件内网IPv4地址。</li>
// <li>tag-key - String -是否必填:否- 过滤条件按照标签键进行过滤。使用请参考示例2</li>
// <li>tag:tag-key - String - 是否必填:否 - (过滤条件)按照标签键值对进行过滤。 tag-key使用具体的标签键进行替换。使用请参考示例3。</li>
Filters []*Filter `json:"Filters,omitempty" name:"Filters" list`
// 偏移量默认为0。
@ -3755,6 +4179,8 @@ type DescribeRouteTablesRequest struct {
// <li>route-table-name - String - (过滤条件)路由表名称。</li>
// <li>vpc-id - String - 过滤条件VPC实例ID形如vpc-f49l6u0z。</li>
// <li>association.main - String - (过滤条件)是否主路由表。</li>
// <li>tag-key - String -是否必填:否- (过滤条件)按照标签键进行过滤。</li>
// <li>tag:tag-key - String - 是否必填:否 - (过滤条件)按照标签键值对进行过滤。 tag-key使用具体的标签键进行替换。使用请参考示例2。</li>
Filters []*Filter `json:"Filters,omitempty" name:"Filters" list`
// 偏移量。
@ -3878,8 +4304,11 @@ type DescribeSecurityGroupsRequest struct {
SecurityGroupIds []*string `json:"SecurityGroupIds,omitempty" name:"SecurityGroupIds" list`
// 过滤条件参数不支持同时指定SecurityGroupIds和Filters。
// <li>security-group-id - String - 过滤条件安全组ID。</li>
// <li>project-id - Integer - 过滤条件项目id。</li>
// <li>security-group-name - String - (过滤条件)安全组名称。</li>
// <li>tag-key - String -是否必填:否- 过滤条件按照标签键进行过滤。使用请参考示例2。</li>
// <li>tag:tag-key - String - 是否必填:否 - (过滤条件)按照标签键值对进行过滤。 tag-key使用具体的标签键进行替换。使用请参考示例3。</li>
Filters []*Filter `json:"Filters,omitempty" name:"Filters" list`
// 偏移量。
@ -4032,6 +4461,8 @@ type DescribeSubnetsRequest struct {
// <li>is-remote-vpc-snat - Boolean - 过滤条件是否为VPC SNAT地址池子网。</li>
// <li>subnet-name - String - (过滤条件)子网名称。</li>
// <li>zone - String - (过滤条件)可用区。</li>
// <li>tag-key - String -是否必填:否- (过滤条件)按照标签键进行过滤。</li>
// <li>tag:tag-key - String - 是否必填:否 - (过滤条件)按照标签键值对进行过滤。 tag-key使用具体的标签键进行替换。使用请参考示例2。</li>
Filters []*Filter `json:"Filters,omitempty" name:"Filters" list`
// 偏移量
@ -4074,6 +4505,49 @@ func (r *DescribeSubnetsResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeTaskResultRequest struct {
*tchttp.BaseRequest
// 异步任务ID
TaskId *uint64 `json:"TaskId,omitempty" name:"TaskId"`
// 计费订单号
DealName *string `json:"DealName,omitempty" name:"DealName"`
}
func (r *DescribeTaskResultRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DescribeTaskResultRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeTaskResultResponse struct {
*tchttp.BaseResponse
Response *struct {
// 任务ID
TaskId *uint64 `json:"TaskId,omitempty" name:"TaskId"`
// 执行结果,包括"SUCCESS", "FAILED", "RUNNING"
Result *string `json:"Result,omitempty" name:"Result"`
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *DescribeTaskResultResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DescribeTaskResultResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DescribeVpcIpv6AddressesRequest struct {
*tchttp.BaseRequest
@ -4174,6 +4648,8 @@ type DescribeVpcsRequest struct {
// <li>is-default - String - 过滤条件是否默认VPC。</li>
// <li>vpc-id - String - 过滤条件VPC实例ID形如vpc-f49l6u0z。</li>
// <li>cidr-block - String - 过滤条件vpc的cidr。</li>
// <li>tag-key - String -是否必填:否- (过滤条件)按照标签键进行过滤。</li>
// <li>tag:tag-key - String - 是否必填:否 - (过滤条件)按照标签键值对进行过滤。 tag-key使用具体的标签键进行替换。使用请参考示例2。</li>
Filters []*Filter `json:"Filters,omitempty" name:"Filters" list`
// 偏移量
@ -4326,6 +4802,27 @@ func (r *DescribeVpnGatewaysResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DestinationIpPortTranslationNatRule struct {
// 网络协议,可选值:`TCP`、`UDP`。
IpProtocol *string `json:"IpProtocol,omitempty" name:"IpProtocol"`
// 弹性IP。
PublicIpAddress *string `json:"PublicIpAddress,omitempty" name:"PublicIpAddress"`
// 公网端口。
PublicPort *uint64 `json:"PublicPort,omitempty" name:"PublicPort"`
// 内网地址。
PrivateIpAddress *string `json:"PrivateIpAddress,omitempty" name:"PrivateIpAddress"`
// 内网端口。
PrivatePort *uint64 `json:"PrivatePort,omitempty" name:"PrivatePort"`
// NAT网关转发规则描述。
Description *string `json:"Description,omitempty" name:"Description"`
}
type DetachCcnInstancesRequest struct {
*tchttp.BaseRequest
@ -4480,6 +4977,9 @@ type DirectConnectGateway struct {
// 是否启用BGP。
EnableBGP *bool `json:"EnableBGP,omitempty" name:"EnableBGP"`
// 开启和关闭BGP的community属性。
EnableBGPCommunity *bool `json:"EnableBGPCommunity,omitempty" name:"EnableBGPCommunity"`
}
type DirectConnectGatewayCcnRoute struct {
@ -4591,6 +5091,9 @@ type DisassociateAddressResponse struct {
*tchttp.BaseResponse
Response *struct {
// 异步任务TaskId。可以使用[DescribeTaskResult](https://cloud.tencent.com/document/api/215/36271)接口查询任务状态。
TaskId *string `json:"TaskId,omitempty" name:"TaskId"`
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
@ -4605,6 +5108,43 @@ func (r *DisassociateAddressResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DisassociateNatGatewayAddressRequest struct {
*tchttp.BaseRequest
// NAT网关的ID形如`nat-df45454`。
NatGatewayId *string `json:"NatGatewayId,omitempty" name:"NatGatewayId"`
// 绑定NAT网关的弹性IP数组。
PublicIpAddresses []*string `json:"PublicIpAddresses,omitempty" name:"PublicIpAddresses" list`
}
func (r *DisassociateNatGatewayAddressRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DisassociateNatGatewayAddressRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DisassociateNatGatewayAddressResponse struct {
*tchttp.BaseResponse
Response *struct {
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *DisassociateNatGatewayAddressResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *DisassociateNatGatewayAddressResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type DownloadCustomerGatewayConfigurationRequest struct {
*tchttp.BaseRequest
@ -5307,6 +5847,9 @@ type ModifyAddressAttributeRequest struct {
// 修改后的 EIP 名称。长度上限为20个字符。
AddressName *string `json:"AddressName,omitempty" name:"AddressName"`
// 设定EIP是否直通"TRUE"表示直通,"FALSE"表示非直通。注意该参数仅对EIP直通功能可见的用户可以设定。
EipDirectConnection *string `json:"EipDirectConnection,omitempty" name:"EipDirectConnection"`
}
func (r *ModifyAddressAttributeRequest) ToJsonString() string {
@ -5445,6 +5988,9 @@ type ModifyAddressesBandwidthResponse struct {
*tchttp.BaseResponse
Response *struct {
// 异步任务TaskId。可以使用[DescribeTaskResult](https://cloud.tencent.com/document/api/215/36271)接口查询任务状态。
TaskId *string `json:"TaskId,omitempty" name:"TaskId"`
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
@ -5813,6 +6359,86 @@ func (r *ModifyIpv6AddressesAttributeResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type ModifyNatGatewayAttributeRequest struct {
*tchttp.BaseRequest
// NAT网关的ID形如`nat-df45454`。
NatGatewayId *string `json:"NatGatewayId,omitempty" name:"NatGatewayId"`
// NAT网关的名称形如`test_nat`。
NatGatewayName *string `json:"NatGatewayName,omitempty" name:"NatGatewayName"`
// NAT网关最大外网出带宽(单位:Mbps)。
InternetMaxBandwidthOut *uint64 `json:"InternetMaxBandwidthOut,omitempty" name:"InternetMaxBandwidthOut"`
}
func (r *ModifyNatGatewayAttributeRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *ModifyNatGatewayAttributeRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type ModifyNatGatewayAttributeResponse struct {
*tchttp.BaseResponse
Response *struct {
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *ModifyNatGatewayAttributeResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *ModifyNatGatewayAttributeResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type ModifyNatGatewayDestinationIpPortTranslationNatRuleRequest struct {
*tchttp.BaseRequest
// NAT网关的ID形如`nat-df45454`。
NatGatewayId *string `json:"NatGatewayId,omitempty" name:"NatGatewayId"`
// 源NAT网关的端口转换规则。
SourceNatRule *DestinationIpPortTranslationNatRule `json:"SourceNatRule,omitempty" name:"SourceNatRule"`
// 目的NAT网关的端口转换规则。
DestinationNatRule *DestinationIpPortTranslationNatRule `json:"DestinationNatRule,omitempty" name:"DestinationNatRule"`
}
func (r *ModifyNatGatewayDestinationIpPortTranslationNatRuleRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *ModifyNatGatewayDestinationIpPortTranslationNatRuleRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type ModifyNatGatewayDestinationIpPortTranslationNatRuleResponse struct {
*tchttp.BaseResponse
Response *struct {
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *ModifyNatGatewayDestinationIpPortTranslationNatRuleResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *ModifyNatGatewayDestinationIpPortTranslationNatRuleResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type ModifyNetworkInterfaceAttributeRequest struct {
*tchttp.BaseRequest
@ -6262,6 +6888,89 @@ func (r *ModifyVpnGatewayAttributeResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type NatGateway struct {
// NAT网关的ID。
NatGatewayId *string `json:"NatGatewayId,omitempty" name:"NatGatewayId"`
// NAT网关的名称。
NatGatewayName *string `json:"NatGatewayName,omitempty" name:"NatGatewayName"`
// NAT网关创建的时间。
CreatedTime *string `json:"CreatedTime,omitempty" name:"CreatedTime"`
// NAT网关的状态。
// 'PENDING':生产中,'DELETING':删除中,'AVAILABLE':运行中,'UPDATING':升级中,
// FAILED失败。
State *string `json:"State,omitempty" name:"State"`
// 网关最大外网出带宽(单位:Mbps)。
InternetMaxBandwidthOut *uint64 `json:"InternetMaxBandwidthOut,omitempty" name:"InternetMaxBandwidthOut"`
// 网关并发连接上限。
MaxConcurrentConnection *uint64 `json:"MaxConcurrentConnection,omitempty" name:"MaxConcurrentConnection"`
// 绑定NAT网关的公网IP对象数组。
PublicIpAddressSet []*NatGatewayAddress `json:"PublicIpAddressSet,omitempty" name:"PublicIpAddressSet" list`
// NAT网关网络状态。“AVAILABLE”:运行中, “UNAVAILABLE”:不可用, “INSUFFICIENT”:欠费停服。
NetworkState *string `json:"NetworkState,omitempty" name:"NetworkState"`
// NAT网关的端口转发规则。
DestinationIpPortTranslationNatRuleSet []*DestinationIpPortTranslationNatRule `json:"DestinationIpPortTranslationNatRuleSet,omitempty" name:"DestinationIpPortTranslationNatRuleSet" list`
// VPC实例ID。
VpcId *string `json:"VpcId,omitempty" name:"VpcId"`
// NAT网关所在的可用区。
Zone *string `json:"Zone,omitempty" name:"Zone"`
}
type NatGatewayAddress struct {
// 弹性公网IPEIP的唯一 ID形如`eip-11112222`。
AddressId *string `json:"AddressId,omitempty" name:"AddressId"`
// 外网IP地址形如`123.121.34.33`。
PublicIpAddress *string `json:"PublicIpAddress,omitempty" name:"PublicIpAddress"`
// 资源封堵状态。true表示弹性ip处于封堵状态false表示弹性ip处于未封堵状态。
IsBlocked *bool `json:"IsBlocked,omitempty" name:"IsBlocked"`
}
type NatGatewayDestinationIpPortTranslationNatRule struct {
// 网络协议,可选值:`TCP`、`UDP`。
IpProtocol *string `json:"IpProtocol,omitempty" name:"IpProtocol"`
// 弹性IP。
PublicIpAddress *string `json:"PublicIpAddress,omitempty" name:"PublicIpAddress"`
// 公网端口。
PublicPort *uint64 `json:"PublicPort,omitempty" name:"PublicPort"`
// 内网地址。
PrivateIpAddress *string `json:"PrivateIpAddress,omitempty" name:"PrivateIpAddress"`
// 内网端口。
PrivatePort *uint64 `json:"PrivatePort,omitempty" name:"PrivatePort"`
// NAT网关转发规则描述。
Description *string `json:"Description,omitempty" name:"Description"`
// NAT网关的ID。
// 注意:此字段可能返回 null表示取不到有效值。
NatGatewayId *string `json:"NatGatewayId,omitempty" name:"NatGatewayId"`
// 私有网络VPC的ID。
// 注意:此字段可能返回 null表示取不到有效值。
VpcId *string `json:"VpcId,omitempty" name:"VpcId"`
// NAT网关转发规则创建时间。
// 注意:此字段可能返回 null表示取不到有效值。
CreatedTime *string `json:"CreatedTime,omitempty" name:"CreatedTime"`
}
type NetworkInterface struct {
// 弹性网卡实例ID例如eni-f1xjkw1b。
@ -6311,6 +7020,9 @@ type NetworkInterface struct {
// `IPv6`地址列表。
Ipv6AddressSet []*Ipv6Address `json:"Ipv6AddressSet,omitempty" name:"Ipv6AddressSet" list`
// 标签键值对。
TagSet []*Tag `json:"TagSet,omitempty" name:"TagSet" list`
}
type NetworkInterfaceAttachment struct {
@ -6434,6 +7146,9 @@ type ReleaseAddressesResponse struct {
*tchttp.BaseResponse
Response *struct {
// 异步任务TaskId。可以使用[DescribeTaskResult](https://cloud.tencent.com/document/api/215/36271)接口查询任务状态。
TaskId *string `json:"TaskId,omitempty" name:"TaskId"`
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
@ -6750,6 +7465,43 @@ func (r *ResetAttachCcnInstancesResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type ResetNatGatewayConnectionRequest struct {
*tchttp.BaseRequest
// NAT网关ID。
NatGatewayId *string `json:"NatGatewayId,omitempty" name:"NatGatewayId"`
// NAT网关并发连接上限形如1000000、3000000、10000000。
MaxConcurrentConnection *uint64 `json:"MaxConcurrentConnection,omitempty" name:"MaxConcurrentConnection"`
}
func (r *ResetNatGatewayConnectionRequest) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *ResetNatGatewayConnectionRequest) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type ResetNatGatewayConnectionResponse struct {
*tchttp.BaseResponse
Response *struct {
// 唯一请求 ID每次请求都会返回。定位问题时需要提供该次请求的 RequestId。
RequestId *string `json:"RequestId,omitempty" name:"RequestId"`
} `json:"Response"`
}
func (r *ResetNatGatewayConnectionResponse) ToJsonString() string {
b, _ := json.Marshal(r)
return string(b)
}
func (r *ResetNatGatewayConnectionResponse) FromJsonString(s string) error {
return json.Unmarshal([]byte(s), &r)
}
type ResetRoutesRequest struct {
*tchttp.BaseRequest
@ -7021,6 +7773,9 @@ type SecurityGroupPolicy struct {
// 网段或IP(互斥)。
CidrBlock *string `json:"CidrBlock,omitempty" name:"CidrBlock"`
// 网段或IPv6(互斥)。
Ipv6CidrBlock *string `json:"Ipv6CidrBlock,omitempty" name:"Ipv6CidrBlock"`
// 安全组实例ID例如sg-ohuuioma。
SecurityGroupId *string `json:"SecurityGroupId,omitempty" name:"SecurityGroupId"`
@ -7032,6 +7787,9 @@ type SecurityGroupPolicy struct {
// 安全组规则描述。
PolicyDescription *string `json:"PolicyDescription,omitempty" name:"PolicyDescription"`
// 安全组最近修改时间。
ModifyTime *string `json:"ModifyTime,omitempty" name:"ModifyTime"`
}
type SecurityGroupPolicySet struct {
@ -7418,6 +8176,10 @@ type Vpc struct {
// 标签键值对
TagSet []*Tag `json:"TagSet,omitempty" name:"TagSet" list`
// 辅助CIDR
// 注意:此字段可能返回 null表示取不到有效值。
AssistantCidrSet []*AssistantCidr `json:"AssistantCidrSet,omitempty" name:"AssistantCidrSet" list`
}
type VpcIpv6Address struct {

2
vendor/modules.txt vendored
View File

@ -484,7 +484,7 @@ github.com/stretchr/testify/assert
github.com/stretchr/testify/require
# github.com/temoto/robotstxt v1.1.1
github.com/temoto/robotstxt
# github.com/tencentcloud/tencentcloud-sdk-go v3.0.71+incompatible
# github.com/tencentcloud/tencentcloud-sdk-go v3.0.94+incompatible
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http

View File

@ -18,8 +18,7 @@ customized images based on an existing base images.
The following configuration options are available for building Tencentcloud images.
In addition to the options listed here,
a [communicator](/docs/templates/communicator.html) can be configured for this
builder.
a [communicator](/docs/templates/communicator.html) can be configured for this builder.
### Required:
@ -31,15 +30,15 @@ builder.
- `region` (string) - The region where your cvm will be launch. You should
reference [Region and Zone](https://intl.cloud.tencent.com/document/product/213/6091)
for parameter taking.
for parameter taking.
- `zone` (string) - The zone where your cvm will be launch. You should
reference [Region and Zone](https://intl.cloud.tencent.com/document/product/213/6091)
for parameter taking.
for parameter taking.
- `instance_type` (string) - The instance type your cvm will be launched by.
You should reference [Instace Type](https://intl.cloud.tencent.com/document/product/213/11518)
for parameter taking.
for parameter taking.
- `source_image_id` (string) - The base image id of Image you want to create
your customized image from.
@ -50,25 +49,20 @@ builder.
### Optional:
- `force_poweroff` (boolean) - Whether to force power off cvm when create image.
Default value is `false`.
- `force_poweroff` (boolean) - Indicates whether to perform a forced shutdown to
create an image when soft shutdown fails. Default value is `false`.
Your cvm will try to shutdown normally; if shutdown failed and `force_poweroff`
set, your cvm will be powered off, otherwise task will fail.
- `image_description` (string) - Image description. It should no more than 60 characters.
- `image_description` (string) - Image description.
- `reboot` (boolean) - Whether shutdown cvm to create Image. Default value is
`false`.
If `reboot` is not set and cvm is running, create image task will fail.
- `reboot` (boolean, **deprecated**) - Whether shutdown cvm to create Image.
Please refer to parameter `force_poweroff`.
- `sysprep` (boolean) - Whether enable Sysprep during creating windows image.
- `image_copy_regions` (array of strings) - regions that will be copied to after
- `image_copy_regions` (array of strings) - Regions that will be copied to after
your image created.
- `image_share_accounts` (array of strings) - accounts that will be shared to
- `image_share_accounts` (array of strings) - Accounts that will be shared to
after your image created.
- `skip_region_validation` (boolean) - Do not check region and zone when validate.
@ -78,6 +72,9 @@ builder.
If not set, you could access your cvm from the same vpc.
- `internet_max_bandwidth_out` (number) - Max bandwidth out your cvm will be launched by(in MB).
values can be set between 1 ~ 100.
- `instance_name` (string) - Instance name.
- `disk_type` (string) - Root disk type your cvm will be launched by. you could
@ -103,7 +100,7 @@ builder.
- `vpc_name` (string) - Specify vpc name you will create. if `vpc_id` is not set, packer will
create a vpc for you named this parameter.
- `cidr_block` (boolean) - Specify cider block of the vpc you will create if `vpc_id` not set
- `cidr_block` (boolean) - Specify cider block of the vpc you will create if `vpc_id` is not set.
- `subnet_id` (string) - Specify subnet your cvm will be launched by.
@ -111,14 +108,11 @@ builder.
create a subnet for you named this parameter.
- `subnect_cidr_block` (boolean) - Specify cider block of the subnet you will create if
`subnet_id` not set
- `internet_max_bandwidth_out` (number) - Max bandwidth out your cvm will be launched by(in MB).
values can be set between 1 ~ 100.
`subnet_id` is not set.
- `security_group_id` (string) - Specify security group your cvm will be launched by.
- `security_group_name` (string) - Specify security name you will create if `security_group_id` not set.
- `security_group_name` (string) - Specify security name you will create if `security_group_id` is not set.
- `user_data` (string) - userdata.
@ -139,29 +133,34 @@ Here is a basic example for Tencentcloud.
"secret_id": "{{env `TENCENTCLOUD_ACCESS_KEY`}}",
"secret_key": "{{env `TENCENTCLOUD_SECRET_KEY`}}"
},
"builders": [{
"type": "tencentcloud-cvm",
"secret_id": "{{user `secret_id`}}",
"secret_key": "{{user `secret_key`}}",
"region": "ap-guangzhou",
"zone": "ap-guangzhou-3",
"instance_type": "S3.SMALL1",
"source_image_id": "img-oikl1tzv",
"ssh_username" : "root",
"image_name": "packerTest2",
"packer_debug": true,
"associate_public_ip_address": true,
"run_tags": {
"good": "luck"
"builders": [
{
"type": "tencentcloud-cvm",
"secret_id": "{{user `secret_id`}}",
"secret_key": "{{user `secret_key`}}",
"region": "ap-guangzhou",
"zone": "ap-guangzhou-4",
"instance_type": "S4.SMALL1",
"source_image_id": "img-oikl1tzv",
"ssh_username": "root",
"image_name": "PackerTest",
"disk_type": "CLOUD_PREMIUM",
"packer_debug": true,
"associate_public_ip_address": true,
"run_tags": {
"good": "luck"
}
}
}],
"provisioners": [{
"type": "shell",
"inline": [
"sleep 30",
"yum install redis.x86_64 -y"
]
}]
],
"provisioners": [
{
"type": "shell",
"inline": [
"sleep 30",
"yum install redis.x86_64 -y"
]
}
]
}
```

View File

@ -42,7 +42,7 @@
- `internet_max_bandwidth_out` (int64) - Max bandwidth out your cvm will be launched by(in MB).
values can be set between 1 ~ 100.
- `security_group_id` (string) - Specify security group your cvm will be launched by.
- `security_group_id` (string) - Specify securitygroup your cvm will be launched by.
- `security_group_name` (string) - Specify security name you will create if security_group_id not set.