From 6fb8988d088160935495d1518b4f1b77e6a5d885 Mon Sep 17 00:00:00 2001 From: Li Kexian Date: Mon, 21 Oct 2019 13:21:21 +0800 Subject: [PATCH] we added retry on remote api call to improve the user experience --- builder/tencentcloud/cvm/access_config.go | 57 +- builder/tencentcloud/cvm/artifact.go | 38 +- builder/tencentcloud/cvm/builder.go | 17 +- builder/tencentcloud/cvm/common.go | 140 +++- builder/tencentcloud/cvm/image_config.go | 12 +- builder/tencentcloud/cvm/image_config_test.go | 1 - builder/tencentcloud/cvm/run_config.go | 23 +- builder/tencentcloud/cvm/run_config_test.go | 5 + .../cvm/step_check_source_image.go | 30 +- .../tencentcloud/cvm/step_config_key_pair.go | 84 +- .../cvm/step_config_security_group.go | 90 +- .../tencentcloud/cvm/step_config_subnet.go | 101 ++- builder/tencentcloud/cvm/step_config_vpc.go | 86 +- builder/tencentcloud/cvm/step_copy_image.go | 23 +- builder/tencentcloud/cvm/step_create_image.go | 84 +- .../cvm/step_detach_temp_key_pair.go | 40 +- builder/tencentcloud/cvm/step_pre_validate.go | 36 +- builder/tencentcloud/cvm/step_run_instance.go | 84 +- builder/tencentcloud/cvm/step_share_image.go | 62 +- .../tencentcloud/basic-with-data-disk.json | 64 +- examples/tencentcloud/basic.json | 52 +- examples/tencentcloud/centos.json | 65 +- go.mod | 2 +- go.sum | 6 +- .../tencentcloud/common/client.go | 35 +- .../tencentcloud/common/http/request.go | 15 +- .../tencentcloud/common/http/response.go | 17 +- .../common/profile/client_profile.go | 8 +- .../common/profile/http_profile.go | 6 +- .../tencentcloud/common/sign.go | 19 +- .../tencentcloud/cvm/v20170312/client.go | 83 +- .../tencentcloud/cvm/v20170312/models.go | 357 +++++++- .../tencentcloud/vpc/v20170312/client.go | 330 +++++++- .../tencentcloud/vpc/v20170312/models.go | 772 +++++++++++++++++- vendor/modules.txt | 2 +- .../docs/builders/tencentcloud-cvm.html.md | 89 +- ...TencentCloudRunConfig-not-required.html.md | 2 +- 37 files changed, 2316 insertions(+), 621 deletions(-) diff --git a/builder/tencentcloud/cvm/access_config.go b/builder/tencentcloud/cvm/access_config.go index cb4790131..9dbe482e4 100644 --- a/builder/tencentcloud/cvm/access_config.go +++ b/builder/tencentcloud/cvm/access_config.go @@ -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) } diff --git a/builder/tencentcloud/cvm/artifact.go b/builder/tencentcloud/cvm/artifact.go index 964f8c8a7..b5c38f579 100644 --- a/builder/tencentcloud/cvm/artifact.go +++ b/builder/tencentcloud/cvm/artifact.go @@ -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 } diff --git a/builder/tencentcloud/cvm/builder.go b/builder/tencentcloud/cvm/builder.go index 9b05846b3..9fe8abb74 100644 --- a/builder/tencentcloud/cvm/builder.go +++ b/builder/tencentcloud/cvm/builder.go @@ -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 } diff --git a/builder/tencentcloud/cvm/common.go b/builder/tencentcloud/cvm/common.go index 209ae6319..6b2f3b374 100644 --- a/builder/tencentcloud/cvm/common.go +++ b/builder/tencentcloud/cvm/common.go @@ -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 +} diff --git a/builder/tencentcloud/cvm/image_config.go b/builder/tencentcloud/cvm/image_config.go index 5311f4254..353675d0f 100644 --- a/builder/tencentcloud/cvm/image_config.go +++ b/builder/tencentcloud/cvm/image_config.go @@ -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) -} diff --git a/builder/tencentcloud/cvm/image_config_test.go b/builder/tencentcloud/cvm/image_config_test.go index 53f9240b7..505dcf3a5 100644 --- a/builder/tencentcloud/cvm/image_config_test.go +++ b/builder/tencentcloud/cvm/image_config_test.go @@ -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) } - } diff --git a/builder/tencentcloud/cvm/run_config.go b/builder/tencentcloud/cvm/run_config.go index 2e4bc3cfe..848566bde 100644 --- a/builder/tencentcloud/cvm/run_config.go +++ b/builder/tencentcloud/cvm/run_config.go @@ -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 } diff --git a/builder/tencentcloud/cvm/run_config_test.go b/builder/tencentcloud/cvm/run_config_test.go index d6ffb889b..8f62c9f90 100644 --- a/builder/tencentcloud/cvm/run_config_test.go +++ b/builder/tencentcloud/cvm/run_config_test.go @@ -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) } diff --git a/builder/tencentcloud/cvm/step_check_source_image.go b/builder/tencentcloud/cvm/step_check_source_image.go index 342373885..f9af0bf24 100644 --- a/builder/tencentcloud/cvm/step_check_source_image.go +++ b/builder/tencentcloud/cvm/step_check_source_image.go @@ -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) {} diff --git a/builder/tencentcloud/cvm/step_config_key_pair.go b/builder/tencentcloud/cvm/step_config_key_pair.go index dfaa97a0d..a4ae97159 100644 --- a/builder/tencentcloud/cvm/step_config_key_pair.go +++ b/builder/tencentcloud/cvm/step_config_key_pair.go @@ -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)) } } } diff --git a/builder/tencentcloud/cvm/step_config_security_group.go b/builder/tencentcloud/cvm/step_config_security_group.go index 2b107615a..97d70e3c1 100644 --- a/builder/tencentcloud/cvm/step_config_security_group.go +++ b/builder/tencentcloud/cvm/step_config_security_group.go @@ -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)) } } diff --git a/builder/tencentcloud/cvm/step_config_subnet.go b/builder/tencentcloud/cvm/step_config_subnet.go index a200591da..91ab42b7f 100644 --- a/builder/tencentcloud/cvm/step_config_subnet.go +++ b/builder/tencentcloud/cvm/step_config_subnet.go @@ -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)) } } diff --git a/builder/tencentcloud/cvm/step_config_vpc.go b/builder/tencentcloud/cvm/step_config_vpc.go index 46630278a..707afb467 100644 --- a/builder/tencentcloud/cvm/step_config_vpc.go +++ b/builder/tencentcloud/cvm/step_config_vpc.go @@ -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)) } } diff --git a/builder/tencentcloud/cvm/step_copy_image.go b/builder/tencentcloud/cvm/step_copy_image.go index e71a9f8cd..b8494f354 100644 --- a/builder/tencentcloud/cvm/step_copy_image.go +++ b/builder/tencentcloud/cvm/step_copy_image.go @@ -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) {} diff --git a/builder/tencentcloud/cvm/step_create_image.go b/builder/tencentcloud/cvm/step_create_image.go index 1d162fa36..9c4b1e7b3 100644 --- a/builder/tencentcloud/cvm/step_create_image.go +++ b/builder/tencentcloud/cvm/step_create_image.go @@ -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)) } } diff --git a/builder/tencentcloud/cvm/step_detach_temp_key_pair.go b/builder/tencentcloud/cvm/step_detach_temp_key_pair.go index ea1feff73..dd9bc5a1b 100644 --- a/builder/tencentcloud/cvm/step_detach_temp_key_pair.go +++ b/builder/tencentcloud/cvm/step_detach_temp_key_pair.go @@ -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) {} diff --git a/builder/tencentcloud/cvm/step_pre_validate.go b/builder/tencentcloud/cvm/step_pre_validate.go index ede5293df..7bee5d9ea 100644 --- a/builder/tencentcloud/cvm/step_pre_validate.go +++ b/builder/tencentcloud/cvm/step_pre_validate.go @@ -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 } diff --git a/builder/tencentcloud/cvm/step_run_instance.go b/builder/tencentcloud/cvm/step_run_instance.go index 224a62425..b43e1fbf6 100644 --- a/builder/tencentcloud/cvm/step_run_instance.go +++ b/builder/tencentcloud/cvm/step_run_instance.go @@ -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)) } } diff --git a/builder/tencentcloud/cvm/step_share_image.go b/builder/tencentcloud/cvm/step_share_image.go index ffbe3ab9a..f5d4986b8 100644 --- a/builder/tencentcloud/cvm/step_share_image.go +++ b/builder/tencentcloud/cvm/step_share_image.go @@ -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)) } } diff --git a/examples/tencentcloud/basic-with-data-disk.json b/examples/tencentcloud/basic-with-data-disk.json index 695a68014..9f78afdbe 100644 --- a/examples/tencentcloud/basic-with-data-disk.json +++ b/examples/tencentcloud/basic-with-data-disk.json @@ -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" + ] + } + ] +} \ No newline at end of file diff --git a/examples/tencentcloud/basic.json b/examples/tencentcloud/basic.json index 4e90efd36..09663ebbc 100644 --- a/examples/tencentcloud/basic.json +++ b/examples/tencentcloud/basic.json @@ -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" + ] + } + ] +} \ No newline at end of file diff --git a/examples/tencentcloud/centos.json b/examples/tencentcloud/centos.json index 6b4d13bd5..1d55f3fe7 100644 --- a/examples/tencentcloud/centos.json +++ b/examples/tencentcloud/centos.json @@ -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 + } + ] } \ No newline at end of file diff --git a/go.mod b/go.mod index f6fb13583..288e877b7 100644 --- a/go.mod +++ b/go.mod @@ -131,7 +131,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 diff --git a/go.sum b/go.sum index 227d12cb6..d5a823c15 100644 --- a/go.sum +++ b/go.sum @@ -57,8 +57,6 @@ github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.16.22/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.22.2 h1:uYP58k2Cd9y1qBy8CxTe5ADmdi4kANm8Ul8ch3kkIcQ= -github.com/aws/aws-sdk-go v1.22.2/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.24.1 h1:B2NRyTV1/+h+Dg8Bh7vnuvW6QZz/NBL+uzgC2uILDMI= github.com/aws/aws-sdk-go v1.24.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/azr/flock v0.0.0-20190823144736-958d66434653 h1:2H3Cu0cbG8iszfcgnANwC/cm0YkPJIQvaJ9/tSpwh9o= @@ -396,8 +394,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= diff --git a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/client.go b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/client.go index 92b2d7175..96a9644b1 100644 --- a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/client.go +++ b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/client.go @@ -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 } diff --git a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http/request.go b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http/request.go index 4774013fa..cdfbe7ec1 100644 --- a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http/request.go +++ b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http/request.go @@ -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 diff --git a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http/response.go b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http/response.go index c8e27f7f5..288f21bdf 100644 --- a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http/response.go +++ b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http/response.go @@ -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 } diff --git a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile/client_profile.go b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile/client_profile.go index 0fc71750b..21069ff99 100644 --- a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile/client_profile.go +++ b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile/client_profile.go @@ -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", } } diff --git a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile/http_profile.go b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile/http_profile.go index 8d4bf8f57..cf633a8a0 100644 --- a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile/http_profile.go +++ b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile/http_profile.go @@ -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", } } diff --git a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/sign.go b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/sign.go index 63efd9227..0aa7b7355 100644 --- a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/sign.go +++ b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/sign.go @@ -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() } diff --git a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312/client.go b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312/client.go index 3305127e1..24f87ebaf 100644 --- a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312/client.go +++ b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312/client.go @@ -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{}, diff --git a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312/models.go b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312/models.go index aef3f7b30..d159bc4e2 100644 --- a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312/models.go +++ b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312/models.go @@ -243,19 +243,17 @@ type CreateImageRequest struct { // 镜像描述 ImageDescription *string `json:"ImageDescription,omitempty" name:"ImageDescription"` - // 软关机失败时是否执行强制关机以制作镜像 + // 是否执行强制关机以制作镜像。 + // 取值范围:
  • TRUE:表示关机之后制作镜像
  • FALSE:表示开机状态制作镜像

    默认取值:FALSE。

    开机状态制作镜像,可能导致部分数据未备份,影响数据安全。 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`。详细的过滤条件如下: //
  • image-id - String - 是否必填: 否 - (过滤条件)按照镜像ID进行过滤
  • - //
  • image-type - String - 是否必填: 否 - (过滤条件)按照镜像类型进行过滤。取值范围:详见[镜像类型](https://cloud.tencent.com/document/product/213/9452#image_type)。
  • - //
  • image-state - String - 是否必填: 否 - (过滤条件)按照镜像状态进行过滤。取值范围:详见[镜像状态](https://cloud.tencent.com/document/product/213/9452#image_state)。
  • + //
  • image-type - String - 是否必填: 否 - (过滤条件)按照镜像类型进行过滤。取值范围: + // PRIVATE_IMAGE: 私有镜像 (本帐户创建的镜像) + // PUBLIC_IMAGE: 公共镜像 (腾讯云官方镜像) + // MARKET_IMAGE: 服务市场 (服务市场提供的镜像) + // SHARED_IMAGE: 共享镜像(其他账户共享给本帐户的镜像) 。
  • 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"` + + //
  • zone
  • + //

    按照预留实例计费可购买的【可用区】进行过滤。形如:ap-guangzhou-1。

    类型:String

    必选:否

    可选项:可用区列表

    + //
  • duration
  • + //

    按照预留实例计费【有效期】即预留实例计费购买时长进行过滤。形如:31536000。

    类型:Integer

    计量单位:秒

    必选:否

    可选项:31536000 (1年) | 94608000(3年)

    + //
  • instance-type
  • + //

    按照【预留实例计费类型】进行过滤。形如:S3.MEDIUM4。

    类型:String

    必选:否

    可选项:预留实例计费类型列表

    + //
  • offering-type
  • + //

    按照【付款类型】进行过滤。形如:All Upfront (预付全部费用)。

    类型:String

    必选:否

    可选项:All Upfront (预付全部费用)

    + //
  • product-description
  • + //

    按照预留实例计费的【平台描述】(即操作系统)进行过滤。形如:linux。

    类型:String

    必选:否

    可选项:linux

    + //
  • reserved-instances-offering-id
  • + //

    按照【预留实例计费配置ID】进行过滤。形如:650c138f-ae7e-4750-952a-96841d6e9fc1。

    类型:String

    必选:否

    + // 每次请求的`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"` + + //
  • zone
  • + //

    按照预留实例计费可购买的【可用区】进行过滤。形如:ap-guangzhou-1。

    类型:String

    必选:否

    可选项:可用区列表

    + //
  • duration
  • + //

    按照预留实例计费【有效期】即预留实例计费购买时长进行过滤。形如:31536000。

    类型:Integer

    计量单位:秒

    必选:否

    可选项:31536000 (1年) | 94608000(3年)

    + //
  • instance-type
  • + //

    按照【预留实例计费类型】进行过滤。形如:S3.MEDIUM4。

    类型:String

    必选:否

    可选项:预留实例计费类型列表

    + //
  • offering-type
  • + //

    按照【付款类型】进行过滤。形如:All Upfront (预付全部费用)。

    类型:String

    必选:否

    可选项:All Upfront (预付全部费用)

    + //
  • product-description
  • + //

    按照预留实例计费的【平台描述】(即操作系统)进行过滤。形如:linux。

    类型:String

    必选:否

    可选项:linux

    + //
  • reserved-instances-id
  • + //

    按照已购买【预留实例计费ID】进行过滤。形如:650c138f-ae7e-4750-952a-96841d6e9fc1。

    类型:String

    必选:否

    + //
  • state
  • + //

    按照已购买【预留实例计费状态】进行过滤。形如:active。

    类型:String

    必选:否

    可选项:active (以创建) | pending (等待被创建) | retired (过期)

    + // 每次请求的`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"` - // 实例计费模式。取值范围:
  • `PREPAID`:表示预付费,即包年包月
  • `POSTPAID_BY_HOUR`:表示后付费,即按量计费
  • `CDHPAID`:`CDH`付费,即只对`CDH`计费,不对`CDH`上的实例计费。 + // 实例计费模式。取值范围:
  • `PREPAID`:表示预付费,即包年包月
  • `POSTPAID_BY_HOUR`:表示后付费,即按量计费
  • `CDHPAID`:`CDH`付费,即只对`CDH`计费,不对`CDH`上的实例计费。
  • `SPOTPAID`:表示竞价实例付费。 InstanceChargeType *string `json:"InstanceChargeType,omitempty" name:"InstanceChargeType"` // 实例系统盘信息。 @@ -2062,6 +2197,24 @@ type Instance struct { // 实例的关机计费模式。 // 取值范围:
  • KEEP_CHARGING:关机继续收费
  • STOP_CHARGING:关机停止收费
  • NOT_APPLICABLE:实例处于非关机状态或者不适用关机停止计费的条件
    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"` + + // 实例的最新操作状态。取值范围:
    + //
  • SUCCESS:表示操作成功
    + //
  • OPERATING:表示操作执行中
    + //
  • 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"` - // 实例计费模式。取值范围:
  • PREPAID:表示预付费,即包年包月
  • POSTPAID_BY_HOUR:表示后付费,即按量计费
  • CDHPAID:表示[CDH](https://cloud.tencent.com/document/product/416)付费,即只对CDH计费,不对CDH上的实例计费。 + // 实例计费模式。取值范围:
  • PREPAID:表示预付费,即包年包月
  • POSTPAID_BY_HOUR:表示后付费,即按量计费
  • CDHPAID:表示[CDH](https://cloud.tencent.com/document/product/416)付费,即只对CDH计费,不对CDH上的实例计费。
  • `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。取值范围:
  • TRUE:表示分配公网IP
  • FALSE:表示不分配公网IP

    当公网带宽大于0Mbps时,可自由选择开通与否,默认开通公网IP;当公网带宽为0,则不允许分配公网IP。 + // 是否分配公网IP。取值范围:
  • TRUE:表示分配公网IP
  • FALSE:表示不分配公网IP

    当公网带宽大于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字符。若不指定该参数,则无法保证请求的幂等性。
    更多详细信息请参阅:如何保证幂等性 + 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 { // 是否在正常重启失败后选择强制重启实例。取值范围:
  • TRUE:表示在正常重启失败后进行强制重启
  • FALSE:表示在正常重启失败后不进行强制重启

    默认取值:FALSE。 ForceReboot *bool `json:"ForceReboot,omitempty" name:"ForceReboot"` + + // 关机类型。取值范围:
  • SOFT:表示软关机
  • HARD:表示硬关机
  • SOFT_FIRST:表示优先软关机,失败再执行硬关机

    默认取值: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。 + // 返回项:预留实例计费类型列表 + InstanceType *string `json:"InstanceType,omitempty" name:"InstanceType"` + + // 预留实例计费可购买的可用区。形如:ap-guangzhou-1。 + // 返回项:可用区列表 + 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。 + // 返回项:可用区列表 + 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。 + // 返回项:预留实例计费类型列表 + 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` - // 实例登录密码。不同操作系统类型密码复杂度限制不一样,具体如下:
  • `Linux`实例密码必须8到16位,至少包括两项`[a-z,A-Z]、[0-9]`和`[( ) ~ ~ ! @ # $ % ^ & * - + = _ | { } [ ] : ; ' < > , . ? /]`中的符号。密码不允许以`/`符号开头。
  • `Windows`实例密码必须12到16位,至少包括三项`[a-z],[A-Z],[0-9]`和`[( ) ~ ~ ! @ # $ % ^ & * - + = _ | { } [ ] : ; ' < > , . ? /]`中的符号。密码不允许以`/`符号开头。
  • 如果实例即包含`Linux`实例又包含`Windows`实例,则密码复杂度限制按照`Windows`实例的限制。 + // 实例登录密码。不同操作系统类型密码复杂度限制不一样,具体如下: + // Linux实例密码必须8-30位,推荐使用12位以上密码,不能以“/”开头,至少包含以下字符中的三种不同字符,字符种类:
  • 小写字母:[a-z]
  • 大写字母:[A-Z]
  • 数字:0-9
  • 特殊字符: ()\`~!@#$%^&\*-+=\_|{}[]:;'<>,.?/: + // Windows实例密码必须12~30位,不能以“/”开头且不包括用户名,至少包含以下字符中的三种不同字符
  • 小写字母:[a-z]
  • 大写字母:[A-Z]
  • 数字: 0-9
  • 特殊字符:()\`~!@#$%^&\*-+=\_|{}[]:;' <>,.?/:
  • 如果实例即包含`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 + // 全网可用区名称如下: + //
  • ap-chongqing-1
  • + //
  • ap-seoul-1
  • + //
  • ap-chengdu-1
  • + //
  • ap-chengdu-2
  • + //
  • ap-hongkong-1
  • + //
  • ap-hongkong-2
  • + //
  • ap-shenzhen-fsi-1
  • + //
  • ap-shenzhen-fsi-2
  • + //
  • ap-shenzhen-fsi-3
  • + //
  • ap-guangzhou-1(售罄)
  • + //
  • ap-guangzhou-2(售罄)
  • + //
  • ap-guangzhou-3
  • + //
  • ap-guangzhou-4
  • + //
  • ap-tokyo-1
  • + //
  • ap-singapore-1
  • + //
  • ap-shanghai-fsi-1
  • + //
  • ap-shanghai-fsi-2
  • + //
  • ap-shanghai-fsi-3
  • + //
  • ap-bangkok-1
  • + //
  • ap-shanghai-1(售罄)
  • + //
  • ap-shanghai-2
  • + //
  • ap-shanghai-3
  • + //
  • ap-shanghai-4
  • + //
  • ap-mumbai-1
  • + //
  • ap-mumbai-2
  • + //
  • eu-moscow-1
  • + //
  • ap-beijing-1
  • + //
  • ap-beijing-2
  • + //
  • ap-beijing-3
  • + //
  • ap-beijing-4
  • + //
  • na-siliconvalley-1
  • + //
  • na-siliconvalley-2
  • + //
  • eu-frankfurt-1
  • + //
  • na-toronto-1
  • + //
  • na-ashburn-1
  • + //
  • na-ashburn-2
  • Zone *string `json:"Zone,omitempty" name:"Zone"` // 可用区描述,例如,广州三区 diff --git a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312/client.go b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312/client.go index 6924ff091..5d878067f 100644 --- a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312/client.go +++ b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312/client.go @@ -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网关绑定弹性IP(EIP)。 +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 网关的路由项,同时也会解绑弹性公网IP(EIP)。 +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{}, diff --git a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312/models.go b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312/models.go index f12064b1b..7a7c1e8d4 100644 --- a/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312/models.go +++ b/vendor/github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312/models.go @@ -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。 + // + InternetServiceProvider *string `json:"InternetServiceProvider,omitempty" name:"InternetServiceProvider"` + + // EIP计费方式。 + // + InternetChargeType *string `json:"InternetChargeType,omitempty" name:"InternetChargeType"` + + // EIP出带宽上限,单位:Mbps。 + // + InternetMaxBandwidthOut *int64 `json:"InternetMaxBandwidthOut,omitempty" name:"InternetMaxBandwidthOut"` + + // EIP类型。默认值:EIP。 + // + AddressType *string `json:"AddressType,omitempty" name:"AddressType"` + + // Anycast发布域。 + // + AnycastZone *string `json:"AnycastZone,omitempty" name:"AnycastZone"` + + // AnycastEIP是否用于绑定负载均衡。 + // + 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地址个数总和不能超过配额数,详见弹性网卡使用限制。 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:普通辅助CIDR,1:容器辅助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/16,172.16.0.0/12,192.168.0.0/16这三个内网网段内。 + // vpc的cidr,只能为10.0.0.0/16,172.16.0.0/16,192.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 { //
  • address-id - String - 是否必填:否 - (过滤条件)按照 EIP 的唯一 ID 过滤。EIP 唯一 ID 形如:eip-11112222。
  • //
  • address-name - String - 是否必填:否 - (过滤条件)按照 EIP 名称过滤。不支持模糊过滤。
  • //
  • address-ip - String - 是否必填:否 - (过滤条件)按照 EIP 的 IP 地址过滤。
  • - //
  • address-status - String - 是否必填:否 - (过滤条件)按照 EIP 的状态过滤。取值范围:[详见EIP状态列表](https://cloud.tencent.com/document/api/213/9452#eip_state)。
  • + //
  • address-status - String - 是否必填:否 - (过滤条件)按照 EIP 的状态过滤。状态包含:'CREATING','BINDING','BIND','UNBINDING','UNBIND','OFFLINING','BIND_ENI'。
  • //
  • instance-id - String - 是否必填:否 - (过滤条件)按照 EIP 绑定的实例 ID 过滤。实例 ID 形如:ins-11112222。
  • //
  • private-ip-address - String - 是否必填:否 - (过滤条件)按照 EIP 绑定的内网 IP 过滤。
  • //
  • network-interface-id - String - 是否必填:否 - (过滤条件)按照 EIP 绑定的弹性网卡 ID 过滤。弹性网卡 ID 形如:eni-11112222。
  • @@ -3037,6 +3307,8 @@ type DescribeCcnsRequest struct { //
  • ccn-name - String - (过滤条件)CCN名称。
  • //
  • ccn-description - String - (过滤条件)CCN描述。
  • //
  • state - String - (过滤条件)实例状态, 'ISOLATED': 隔离中(欠费停服),'AVAILABLE':运行中。
  • + //
  • tag-key - String -是否必填:否- (过滤条件)按照标签键进行过滤。
  • + //
  • tag:tag-key - String - 是否必填:否 - (过滤条件)按照标签键值对进行过滤。 tag-key使用具体的标签键进行替换。使用请参考示例:查询绑定了标签的CCN列表。
  • 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。 + //
  • nat-gateway-id,NAT网关的ID,如`nat-0yi4hekt`
  • + //
  • vpc-id,私有网络VPC的ID,如`vpc-0yi4hekt`
  • + //
  • public-ip-address, 弹性IP,如`139.199.232.238`。
  • + //
  • public-port, 公网端口。
  • + //
  • private-ip-address, 内网IP,如`10.0.0.1`。
  • + //
  • private-port, 内网端口。
  • + //
  • description,规则描述。
  • + 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。 + //
  • nat-gateway-id - String - (过滤条件)协议端口模板实例ID,形如:`nat-123xx454`。
  • + //
  • vpc-id - String - (过滤条件)私有网络 唯一ID,形如:`vpc-123xx454`。
  • + //
  • nat-gateway-name - String - (过滤条件)协议端口模板实例ID,形如:`test_nat`。
  • + 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 { //
  • groups.security-group-id - String - (过滤条件)绑定的安全组实例ID,例如:sg-f9ekbxeq。
  • //
  • network-interface-name - String - (过滤条件)网卡实例名称。
  • //
  • network-interface-description - String - (过滤条件)网卡实例描述。
  • + //
  • address-ip - String - (过滤条件)内网IPv4地址。
  • + //
  • tag-key - String -是否必填:否- (过滤条件)按照标签键进行过滤。使用请参考示例2
  • + //
  • tag:tag-key - String - 是否必填:否 - (过滤条件)按照标签键值对进行过滤。 tag-key使用具体的标签键进行替换。使用请参考示例3。
  • Filters []*Filter `json:"Filters,omitempty" name:"Filters" list` // 偏移量,默认为0。 @@ -3755,6 +4179,8 @@ type DescribeRouteTablesRequest struct { //
  • route-table-name - String - (过滤条件)路由表名称。
  • //
  • vpc-id - String - (过滤条件)VPC实例ID,形如:vpc-f49l6u0z。
  • //
  • association.main - String - (过滤条件)是否主路由表。
  • + //
  • tag-key - String -是否必填:否- (过滤条件)按照标签键进行过滤。
  • + //
  • tag:tag-key - String - 是否必填:否 - (过滤条件)按照标签键值对进行过滤。 tag-key使用具体的标签键进行替换。使用请参考示例2。
  • 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。 + //
  • security-group-id - String - (过滤条件)安全组ID。
  • //
  • project-id - Integer - (过滤条件)项目id。
  • //
  • security-group-name - String - (过滤条件)安全组名称。
  • + //
  • tag-key - String -是否必填:否- (过滤条件)按照标签键进行过滤。使用请参考示例2。
  • + //
  • tag:tag-key - String - 是否必填:否 - (过滤条件)按照标签键值对进行过滤。 tag-key使用具体的标签键进行替换。使用请参考示例3。
  • Filters []*Filter `json:"Filters,omitempty" name:"Filters" list` // 偏移量。 @@ -4032,6 +4461,8 @@ type DescribeSubnetsRequest struct { //
  • is-remote-vpc-snat - Boolean - (过滤条件)是否为VPC SNAT地址池子网。
  • //
  • subnet-name - String - (过滤条件)子网名称。
  • //
  • zone - String - (过滤条件)可用区。
  • + //
  • tag-key - String -是否必填:否- (过滤条件)按照标签键进行过滤。
  • + //
  • tag:tag-key - String - 是否必填:否 - (过滤条件)按照标签键值对进行过滤。 tag-key使用具体的标签键进行替换。使用请参考示例2。
  • 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 { //
  • is-default - String - (过滤条件)是否默认VPC。
  • //
  • vpc-id - String - (过滤条件)VPC实例ID形如:vpc-f49l6u0z。
  • //
  • cidr-block - String - (过滤条件)vpc的cidr。
  • + //
  • tag-key - String -是否必填:否- (过滤条件)按照标签键进行过滤。
  • + //
  • tag:tag-key - String - 是否必填:否 - (过滤条件)按照标签键值对进行过滤。 tag-key使用具体的标签键进行替换。使用请参考示例2。
  • 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 { + + // 弹性公网IP(EIP)的唯一 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 { diff --git a/vendor/modules.txt b/vendor/modules.txt index 70d7a6c98..bcbddfcbb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -475,7 +475,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 diff --git a/website/source/docs/builders/tencentcloud-cvm.html.md b/website/source/docs/builders/tencentcloud-cvm.html.md index 72405ba90..1621fb5d9 100644 --- a/website/source/docs/builders/tencentcloud-cvm.html.md +++ b/website/source/docs/builders/tencentcloud-cvm.html.md @@ -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" + ] + } + ] } ``` diff --git a/website/source/partials/builder/tencentcloud/cvm/_TencentCloudRunConfig-not-required.html.md b/website/source/partials/builder/tencentcloud/cvm/_TencentCloudRunConfig-not-required.html.md index 41ed4918f..3a6953e58 100644 --- a/website/source/partials/builder/tencentcloud/cvm/_TencentCloudRunConfig-not-required.html.md +++ b/website/source/partials/builder/tencentcloud/cvm/_TencentCloudRunConfig-not-required.html.md @@ -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.