From adef8db78efaa7a9ca48c64db981031b0713450d Mon Sep 17 00:00:00 2001 From: Sam Stenvall Date: Tue, 22 Oct 2024 13:09:58 +0300 Subject: [PATCH 1/3] Log the instance ID as soon as it's been created --- builder/tencentcloud/cvm/step_run_instance.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/tencentcloud/cvm/step_run_instance.go b/builder/tencentcloud/cvm/step_run_instance.go index 943eabf6..aee81854 100644 --- a/builder/tencentcloud/cvm/step_run_instance.go +++ b/builder/tencentcloud/cvm/step_run_instance.go @@ -173,7 +173,7 @@ func (s *stepRunInstance) Run(ctx context.Context, state multistep.StateBag) mul } s.instanceId = *resp.Response.InstanceIdSet[0] - Message(state, "Waiting for instance ready", "") + Message(state, fmt.Sprintf("Instance %s created, waiting for instance ready", s.instanceId), "") err = WaitForInstance(ctx, client, s.instanceId, "RUNNING", 1800) if err != nil { From 96a98f9cc9b44c7e5a142da556224ac91f1ba234 Mon Sep 17 00:00:00 2001 From: Sam Stenvall Date: Tue, 22 Oct 2024 13:10:05 +0300 Subject: [PATCH 2/3] Use a unique value as ClientToken for each RunInstances request The purpose of ClientToken is to ensure request idempotency in case the request needs to be retried. This means the value must be unique for all unique RunInstances API calls. When building a template that references the same source multiple times (or multiple different sources), many calls to RunInstances are made. However, the same auto-generated instance name was used as "ClientToken". This changes ClientToken to be unique regardless of whether the user has supplied a unique "instance_name" for each source/build. Fixes https://github.com/hashicorp/packer-plugin-tencentcloud/issues/6 --- builder/tencentcloud/cvm/step_run_instance.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/builder/tencentcloud/cvm/step_run_instance.go b/builder/tencentcloud/cvm/step_run_instance.go index aee81854..f79afefb 100644 --- a/builder/tencentcloud/cvm/step_run_instance.go +++ b/builder/tencentcloud/cvm/step_run_instance.go @@ -11,6 +11,7 @@ import ( "log" "github.com/hashicorp/packer-plugin-sdk/multistep" + "github.com/hashicorp/packer-plugin-sdk/uuid" cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312" ) @@ -125,7 +126,11 @@ func (s *stepRunInstance) Run(ctx context.Context, state multistep.StateBag) mul req.InternetAccessible.BandwidthPackageId = &s.BandwidthPackageId } } - req.InstanceName = &s.InstanceName + + // Generate a unique ClientToken for each RunInstances request + clientToken := uuid.TimeOrderedUUID() + req.ClientToken = &clientToken + loginSettings := cvm.LoginSettings{} if password != "" { loginSettings.Password = &password @@ -135,7 +140,7 @@ func (s *stepRunInstance) Run(ctx context.Context, state multistep.StateBag) mul } req.LoginSettings = &loginSettings req.SecurityGroupIds = []*string{&security_group_id} - req.ClientToken = &s.InstanceName + req.InstanceName = &s.InstanceName req.HostName = &s.HostName req.UserData = &userData req.CamRoleName = &s.CamRoleName From a5919e4eb34b698a679bbbc93fe98a3b1a88cbea Mon Sep 17 00:00:00 2001 From: arunma Date: Thu, 24 Apr 2025 16:03:57 +0800 Subject: [PATCH 3/3] fix: Support SkipCreateImage field to skip creating an image --- .web-docs/components/builder/cvm/README.md | 2 ++ builder/tencentcloud/cvm/builder.go | 13 +++++++++---- builder/tencentcloud/cvm/builder.hcl2spec.go | 2 ++ builder/tencentcloud/cvm/image_config.go | 6 ++++++ builder/tencentcloud/cvm/step_copy_image.go | 16 ++++++++++------ builder/tencentcloud/cvm/step_create_image.go | 9 ++++++++- builder/tencentcloud/cvm/step_pre_validate.go | 6 ++++++ .../cvm/TencentCloudImageConfig-not-required.mdx | 2 ++ 8 files changed, 45 insertions(+), 11 deletions(-) diff --git a/.web-docs/components/builder/cvm/README.md b/.web-docs/components/builder/cvm/README.md index 227bbb61..97f04399 100644 --- a/.web-docs/components/builder/cvm/README.md +++ b/.web-docs/components/builder/cvm/README.md @@ -101,6 +101,8 @@ a [communicator](/packer/docs/templates/legacy_json_templates/communicator) can - `image_tags` (map[string]string) - Key/value pair tags that will be applied to the resulting image. +- `skip_create_image` (bool) - Skip creating an image. When set to true, you don't need to enter target image information, share, copy, etc. The default value is false. + diff --git a/builder/tencentcloud/cvm/builder.go b/builder/tencentcloud/cvm/builder.go index cda74a0c..8c59610e 100644 --- a/builder/tencentcloud/cvm/builder.go +++ b/builder/tencentcloud/cvm/builder.go @@ -90,7 +90,9 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) // Build the steps var steps []multistep.Step steps = []multistep.Step{ - &stepPreValidate{}, + &stepPreValidate{ + b.config.SkipCreateImage, + }, &stepCheckSourceImage{ b.config.SourceImageId, }, @@ -145,13 +147,16 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) // We need this step to detach keypair from instance, otherwise // it always fails to delete the key. &stepDetachTempKeyPair{}, - &stepCreateImage{}, + &stepCreateImage{ + SkipCreateImage: b.config.SkipCreateImage, + }, &stepShareImage{ b.config.ImageShareAccounts, }, &stepCopyImage{ - DesinationRegions: b.config.ImageCopyRegions, - SourceRegion: b.config.Region, + DestinationRegions: b.config.ImageCopyRegions, + SourceRegion: b.config.Region, + SkipCreateImage: b.config.SkipCreateImage, }, } diff --git a/builder/tencentcloud/cvm/builder.hcl2spec.go b/builder/tencentcloud/cvm/builder.hcl2spec.go index 51eadf70..770c338b 100644 --- a/builder/tencentcloud/cvm/builder.hcl2spec.go +++ b/builder/tencentcloud/cvm/builder.hcl2spec.go @@ -36,6 +36,7 @@ type FlatConfig struct { ImageCopyRegions []string `mapstructure:"image_copy_regions" required:"false" cty:"image_copy_regions" hcl:"image_copy_regions"` ImageShareAccounts []string `mapstructure:"image_share_accounts" required:"false" cty:"image_share_accounts" hcl:"image_share_accounts"` ImageTags map[string]string `mapstructure:"image_tags" required:"false" cty:"image_tags" hcl:"image_tags"` + SkipCreateImage *bool `mapstructure:"skip_create_image" required:"false" cty:"skip_create_image" hcl:"skip_create_image"` AssociatePublicIpAddress *bool `mapstructure:"associate_public_ip_address" required:"false" cty:"associate_public_ip_address" hcl:"associate_public_ip_address"` SourceImageId *string `mapstructure:"source_image_id" required:"false" cty:"source_image_id" hcl:"source_image_id"` SourceImageName *string `mapstructure:"source_image_name" required:"false" cty:"source_image_name" hcl:"source_image_name"` @@ -152,6 +153,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "image_copy_regions": &hcldec.AttrSpec{Name: "image_copy_regions", Type: cty.List(cty.String), Required: false}, "image_share_accounts": &hcldec.AttrSpec{Name: "image_share_accounts", Type: cty.List(cty.String), Required: false}, "image_tags": &hcldec.AttrSpec{Name: "image_tags", Type: cty.Map(cty.String), Required: false}, + "skip_create_image": &hcldec.AttrSpec{Name: "skip_create_image", Type: cty.Bool, Required: false}, "associate_public_ip_address": &hcldec.AttrSpec{Name: "associate_public_ip_address", Type: cty.Bool, Required: false}, "source_image_id": &hcldec.AttrSpec{Name: "source_image_id", Type: cty.String, Required: false}, "source_image_name": &hcldec.AttrSpec{Name: "source_image_name", Type: cty.String, Required: false}, diff --git a/builder/tencentcloud/cvm/image_config.go b/builder/tencentcloud/cvm/image_config.go index 036c30dd..9b207c3c 100644 --- a/builder/tencentcloud/cvm/image_config.go +++ b/builder/tencentcloud/cvm/image_config.go @@ -33,11 +33,17 @@ type TencentCloudImageConfig struct { // Key/value pair tags that will be applied to the resulting image. ImageTags map[string]string `mapstructure:"image_tags" required:"false"` skipValidation bool + // Skip creating an image. When set to true, you don't need to enter target image information, share, copy, etc. The default value is false. + SkipCreateImage bool `mapstructure:"skip_create_image" required:"false"` } func (cf *TencentCloudImageConfig) Prepare(ctx *interpolate.Context) []error { var errs []error + if cf.SkipCreateImage { + return nil + } + if cf.ImageName == "" { errs = append(errs, fmt.Errorf("image_name must be specified")) } else if utf8.RuneCountInString(cf.ImageName) > 60 { diff --git a/builder/tencentcloud/cvm/step_copy_image.go b/builder/tencentcloud/cvm/step_copy_image.go index bc481e87..096a1b0e 100644 --- a/builder/tencentcloud/cvm/step_copy_image.go +++ b/builder/tencentcloud/cvm/step_copy_image.go @@ -14,12 +14,16 @@ import ( ) type stepCopyImage struct { - DesinationRegions []string - SourceRegion string + DestinationRegions []string + SourceRegion string + SkipCreateImage bool } func (s *stepCopyImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - if len(s.DesinationRegions) == 0 || (len(s.DesinationRegions) == 1 && s.DesinationRegions[0] == s.SourceRegion) { + if s.SkipCreateImage { + return multistep.ActionContinue + } + if len(s.DestinationRegions) == 0 || (len(s.DestinationRegions) == 1 && s.DestinationRegions[0] == s.SourceRegion) { return multistep.ActionContinue } @@ -28,12 +32,12 @@ func (s *stepCopyImage) Run(ctx context.Context, state multistep.StateBag) multi imageId := state.Get("image").(*cvm.Image).ImageId - Say(state, strings.Join(s.DesinationRegions, ","), "Trying to copy image to") + Say(state, strings.Join(s.DestinationRegions, ","), "Trying to copy image to") req := cvm.NewSyncImagesRequest() req.ImageIds = []*string{imageId} - copyRegions := make([]*string, 0, len(s.DesinationRegions)) - for _, region := range s.DesinationRegions { + copyRegions := make([]*string, 0, len(s.DestinationRegions)) + for _, region := range s.DestinationRegions { if region != s.SourceRegion { copyRegions = append(copyRegions, common.StringPtr(region)) } diff --git a/builder/tencentcloud/cvm/step_create_image.go b/builder/tencentcloud/cvm/step_create_image.go index b337fbeb..1913ed33 100644 --- a/builder/tencentcloud/cvm/step_create_image.go +++ b/builder/tencentcloud/cvm/step_create_image.go @@ -12,7 +12,8 @@ import ( ) type stepCreateImage struct { - imageId string + imageId string + SkipCreateImage bool } func (s *stepCreateImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { @@ -21,6 +22,12 @@ func (s *stepCreateImage) Run(ctx context.Context, state multistep.StateBag) mul config := state.Get("config").(*Config) instance := state.Get("instance").(*cvm.Instance) + // Optionally skip this step + if s.SkipCreateImage { + Say(state, "Skipping image creation step", "") + return multistep.ActionContinue + } + Say(state, config.ImageName, "Trying to create a new image") req := cvm.NewCreateImageRequest() diff --git a/builder/tencentcloud/cvm/step_pre_validate.go b/builder/tencentcloud/cvm/step_pre_validate.go index 4f654e93..4365c4d2 100644 --- a/builder/tencentcloud/cvm/step_pre_validate.go +++ b/builder/tencentcloud/cvm/step_pre_validate.go @@ -12,9 +12,15 @@ import ( ) type stepPreValidate struct { + SkipCreateImage bool } func (s *stepPreValidate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { + // No need to validate the image name if we're not creating an image + if s.SkipCreateImage { + return multistep.ActionContinue + } + config := state.Get("config").(*Config) client := state.Get("cvm_client").(*cvm.Client) diff --git a/docs-partials/builder/tencentcloud/cvm/TencentCloudImageConfig-not-required.mdx b/docs-partials/builder/tencentcloud/cvm/TencentCloudImageConfig-not-required.mdx index b1c3baf0..e2e40837 100644 --- a/docs-partials/builder/tencentcloud/cvm/TencentCloudImageConfig-not-required.mdx +++ b/docs-partials/builder/tencentcloud/cvm/TencentCloudImageConfig-not-required.mdx @@ -15,4 +15,6 @@ - `image_tags` (map[string]string) - Key/value pair tags that will be applied to the resulting image. +- `skip_create_image` (bool) - Skip creating an image. When set to true, you don't need to enter target image information, share, copy, etc. The default value is false. + pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy