From a5919e4eb34b698a679bbbc93fe98a3b1a88cbea Mon Sep 17 00:00:00 2001 From: arunma Date: Thu, 24 Apr 2025 16:03:57 +0800 Subject: [PATCH] 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. +