8000 feat: add datasource image by tongyiming · Pull Request #15 · tencentcloudstack/packer-plugin-tencentcloud · GitHub
[go: up one dir, main page]

Skip to content

feat: add datasource image #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .web-docs/components/builder/cvm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ a [communicator](/packer/docs/templates/legacy_json_templates/communicator) can
reference [Region and Zone](https://intl.cloud.tencent.com/document/product/213/6091)
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.

<!-- End of code generated from the comments of the TencentCloudAccessConfig struct in builder/tencentcloud/cvm/access_config.go; -->


Expand All @@ -37,6 +33,10 @@ a [communicator](/packer/docs/templates/legacy_json_templates/communicator) can
You should reference [Instance Type](https://intl.cloud.tencent.com/document/product/213/11518)
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.

<!-- End of code generated from the comments of the TencentCloudRunConfig struct in builder/tencentcloud/cvm/run_config.go; -->


Expand All @@ -59,6 +59,9 @@ a [communicator](/packer/docs/templates/legacy_json_templates/communicator) can
- `vpc_endpoint` (string) - The endpoint you want to reach the cloud endpoint,
if tce cloud you should set a tce vpc endpoint.

- `tag_endpoint` (string) - The endpoint you want to reach the cloud endpoint,
if tce cloud you should set a tce tag endpoint.

- `security_token` (string) - STS access token, can be set through template or by exporting
as environment variable such as `export TENCENTCLOUD_SECURITY_TOKEN=value`.

Expand Down Expand Up @@ -101,6 +104,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.

- `snapshot_tags` (map[string]string) - Key/value pair tags that will be applied to snapshot.

- `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.

<!-- End of code generated from the comments of the TencentCloudImageConfig struct in builder/tencentcloud/cvm/image_config.go; -->
Expand Down
47 changes: 15 additions & 32 deletions builder/tencentcloud/cvm/access_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
package cvm

import (
"context"
"fmt"
"os"
"strconv"

"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
tag "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tag/v20180813"
vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312"
)

Expand Down Expand Up @@ -76,16 +76,15 @@ type TencentCloudAccessConfig struct {
// reference [Region and Zone](https://intl.cloud.tencent.com/document/product/213/6091)
// for parameter taking.
Region string `mapstructure:"region" required:"true"`
// 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.
Zone string `mapstructure:"zone" required:"true"`
// The endpoint you want to reach the cloud endpoint,
// if tce cloud you should set a tce cvm endpoint.
CvmEndpoint string `mapstructure:"cvm_endpoint" required:"false"`
// The endpoint you want to reach the cloud endpoint,
// if tce cloud you should set a tce vpc endpoint.
VpcEndpoint string `mapstructure:"vpc_endpoint" required:"false"`
// The endpoint you want to reach the cloud endpoint,
// if tce cloud you should set a tce tag endpoint.
TagEndpoint string `mapstructure:"tag_endpoint" required:"false"`
// The region validation can be skipped if this value is true, the default
// value is false.
skipValidation bool
Expand Down Expand Up @@ -126,47 +125,31 @@ type TencentCloudAccessRole struct {
SessionDuration int `mapstructure:"session_duration" required:"false"`
}

func (cf *TencentCloudAccessConfig) Client() (*cvm.Client, *vpc.Client, error) {
func (cf *TencentCloudAccessConfig) Client() (*cvm.Client, *vpc.Client, *tag.Client, error) {
var (
err error
cvm_client *cvm.Client
vpc_client *vpc.Client
resp *cvm.DescribeZonesResponse
tag_client *tag.Client
)

if err = cf.validateRegion(); err != nil {
return nil, nil, err
}

if cf.Zone == "" {
return nil, nil, fmt.Errorf("parameter zone must be set")
return nil, nil, nil, err
}

if cvm_client, err = NewCvmClient(cf); err != nil {
return nil, nil, err
return nil, nil, nil, err
}

if vpc_client, err = NewVpcClient(cf); err != nil {
return nil, nil, err
return nil, nil, nil, err
}

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
}

for _, zone := range resp.Response.ZoneSet {
if cf.Zone == *zone.Zone {
return cvm_client, vpc_client, nil
}
if tag_client, err = NewTagClient(cf); err != nil {
return nil, nil, nil, err
}

return nil, nil, fmt.Errorf("unknown zone: %s", cf.Zone)
return cvm_client, vpc_client, tag_client, nil
}

func (cf *TencentCloudAccessConfig) Prepare(ctx *interpolate.Context) []error {
Expand All @@ -176,9 +159,9 @@ func (cf *TencentCloudAccessConfig) Prepare(ctx *interpolate.Context) []error {
errs = append(errs, err)
}

if (cf.CvmEndpoint != "" && cf.VpcEndpoint == "") ||
(cf.CvmEndpoint == "" && cf.VpcEndpoint != "") {
errs = append(errs, fmt.Errorf("parameter cvm_endpoint and vpc_endpoint must be set simultaneously"))
if !((cf.CvmEndpoint == "" && cf.VpcEndpoint == "" && cf.TagEndpoint == "") ||
(cf.CvmEndpoint != "" && cf.VpcEndpoint != "" && cf.TagEndpoint != "")) {
errs = append(errs, fmt.Errorf("parameter cvm_endpoint, vpc_endpoint and tag_endpoint must be set simultaneously"))
}

if cf.Region == "" {
Expand Down
3 changes: 2 additions & 1 deletion builder/tencentcloud/cvm/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
}

func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) {
cvmClient, vpcClient, err := b.config.Client()
cvmClient, vpcClient, tagClient, err := b.config.Client()
if err != nil {
return nil, err
}
Expand All @@ -84,6 +84,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
state.Put("config", &b.config)
state.Put("cvm_client", cvmClient)
state.Put("vpc_client", vpcClient)
state.Put("tag_client", tagClient)
state.Put("hook", hook)
state.Put("ui", ui)

Expand Down
8 changes: 6 additions & 2 deletions builder/tencentcloud/cvm/builder.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions builder/tencentcloud/cvm/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
sts "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sts/v20180813"
tag "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tag/v20180813"
vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312"
)

Expand All @@ -20,6 +21,7 @@ type TencentCloudClient struct {
vpcConn *vpc.Client
cvmConn *cvm.Client
stsConn *sts.Client
tagConn *tag.Client
}

func (me *TencentCloudClient) UseVpcClient(cpf *profile.ClientProfile) *vpc.Client {
Expand Down Expand Up @@ -53,3 +55,13 @@ func (me *TencentCloudClient) UseStsClient() *sts.Client {

return me.stsConn
}

func (me *TencentCloudClient) UseTagClient(cpf *profile.ClientProfile) *tag.Client {
if me.tagConn != nil {
return me.tagConn
}

me.tagConn, _ = tag.NewClient(me.Credential, me.Region, cpf)

return me.tagConn
}
45 changes: 45 additions & 0 deletions builder/tencentcloud/cvm/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
sts "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sts/v20180813"
tag "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tag/v20180813"
vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312"
)

Expand Down Expand Up @@ -78,6 +79,27 @@ func WaitForImageReady(ctx context.Context, client *cvm.Client, imageName string
}
}

func AddResourceTag(ctx context.Context, client *tag.Client, resourceName string, tags map[string]string) error {
request := tag.NewModifyResourceTagsRequest()
request.Resource = &resourceName
request.ReplaceTags = make([]*tag.Tag, 0, len(tags))
for k, v := range tags {
key := k
value := v
replaceTag := &tag.Tag{
TagKey: &key,
TagValue: &value,
}
request.ReplaceTags = append(request.ReplaceTags, replaceTag)
}

err := Retry(ctx, func(ctx context.Context) error {
_, e := client.ModifyResourceTags(request)
return e
})
return err
}

// GetImageByName get image by image name
func GetImageByName(ctx context.Context, client *cvm.Client, imageName string) (*cvm.Image, error) {
req := cvm.NewDescribeImagesRequest()
Expand Down Expand Up @@ -143,6 +165,22 @@ func NewVpcClient(cf *TencentCloudAccessConfig) (client *vpc.Client, err error)
return
}

// UseTagClient returns a new tag client
func NewTagClient(cf *TencentCloudAccessConfig) (client *tag.Client, err error) {
apiV3Conn, err := packerConfigClient(cf)
if err != nil {
return nil, err
}

tagClientProfile, err := newClientProfile(cf.TagEndpoint)
if err != nil {
return nil, err
}
client = apiV3Conn.UseTagClient(tagClientProfile)

return
}

// CheckResourceIdFormat check resource id format
func CheckResourceIdFormat(resource string, id string) bool {
regex := regexp.MustCompile(fmt.Sprintf("%s-[0-9a-z]{8}$", resource))
Expand Down Expand Up @@ -322,3 +360,10 @@ func IntUint64(i int) *uint64 {
u := uint64(i)
return &u
}
AE88
// BuildTagResourceName builds the Tencent Cloud specific name of a resource description.
// The format is `qcs:project_id:service_type:region:account:resource`.
// For more information, go to https://cloud.tencent.com/document/product/598/10606.
func BuildTagResourceName(serviceType, resourceType, region, id string) string {
return fmt.Sprintf("qcs::%s:%s:uin/:%s/%s", serviceType, region, resourceType, id)
}
7 changes: 6 additions & 1 deletion builder/tencentcloud/cvm/image_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ type TencentCloudImageConfig struct {
// after your image created.
ImageShareAccounts []string `mapstructure:"image_share_accounts" required:"false"`
// Key/value pair tags that will be applied to the resulting image.
ImageTags map[string]string `mapstructure:"image_tags" required:"false"`
ImageTags map[string]string `mapstructure:"image_tags" required:"false"`
// Key/value pair tags that will be applied to snapshot.
SnapshotTags map[string]string `mapstructure:"snapshot_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"`
Expand Down Expand Up @@ -79,6 +81,9 @@ func (cf *TencentCloudImageConfig) Prepare(ctx *interpolate.Context) []error {
if cf.ImageTags == nil {
cf.ImageTags = make(map[string]string)
}
if cf.SnapshotTags == nil {
cf.SnapshotTags = make(map[string]string)
}

if len(errs) > 0 {
return errs
Expand Down
8 changes: 8 additions & 0 deletions builder/tencentcloud/cvm/run_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ type TencentCloudRunConfig struct {
// Communicator settings
Comm communicator.Config `mapstructure:",squash"`
SSHPrivateIp bool `mapstructure:"ssh_private_ip"`
// 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.
Zone string `mapstructure:"zone" required:"true"`
}

var ValidCBSType = []string{
Expand All @@ -125,6 +129,10 @@ func (cf *TencentCloudRunConfig) Prepare(ctx *interpolate.Context) []error {
}

errs := cf.Comm.Prepare(ctx)
if cf.Zone == "" {
errs = append(errs, errors.New("zone must be specified"))
}

if cf.SourceImageId == "" && cf.SourceImageName == "" {
errs = append(errs, errors.New("source_image_id or source_image_name must be specified"))
}
Expand Down
1 change: 1 addition & 0 deletions builder/tencentcloud/cvm/run_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

func testConfig() *TencentCloudRunConfig {
return &TencentCloudRunConfig{
Zone: "ap-guangzhou",
SourceImageId: "img-qwer1234",
InstanceType: "S3.SMALL2",
Comm: communicator.Config{
Expand Down
1 change: 0 additions & 1 deletion builder/tencentcloud/cvm/step_copy_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ func (s *stepCopyImage) Run(ctx context.Context, state multistep.StateBag) multi
cf := &TencentCloudAccessConfig{
SecretId: config.SecretId,
SecretKey: config.SecretKey,
Zone: config.Zone,
CvmEndpoint: config.CvmEndpoint,
SecurityToken: config.SecurityToken,
AssumeRole: TencentCloudAccessRole{
Expand Down
Loading
Loading
0