github.com/hashicorp/packer@v1.14.3/datasource/hcp-packer-version/data.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 //go:generate packer-sdc struct-markdown 5 //go:generate packer-sdc mapstructure-to-hcl2 -type DatasourceOutput,Config 6 package hcp_packer_version 7 8 import ( 9 "context" 10 "fmt" 11 "log" 12 13 hcpPackerModels "github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2023-01-01/models" 14 "github.com/zclconf/go-cty/cty" 15 16 "github.com/hashicorp/hcl/v2/hcldec" 17 "github.com/hashicorp/packer-plugin-sdk/common" 18 "github.com/hashicorp/packer-plugin-sdk/hcl2helper" 19 packersdk "github.com/hashicorp/packer-plugin-sdk/packer" 20 "github.com/hashicorp/packer-plugin-sdk/template/config" 21 hcpapi "github.com/hashicorp/packer/internal/hcp/api" 22 ) 23 24 type Datasource struct { 25 config Config 26 } 27 28 type Config struct { 29 common.PackerConfig `mapstructure:",squash"` 30 // The bucket name in the HCP Packer Registry. 31 BucketName string `mapstructure:"bucket_name" required:"true"` 32 // The channel name in the given bucket to use for retrieving the version. 33 ChannelName string `mapstructure:"channel_name" required:"true"` 34 } 35 36 func (d *Datasource) ConfigSpec() hcldec.ObjectSpec { 37 return d.config.FlatMapstructure().HCL2Spec() 38 } 39 40 func (d *Datasource) Configure(raws ...interface{}) error { 41 err := config.Decode(&d.config, nil, raws...) 42 if err != nil { 43 return err 44 } 45 46 var errs *packersdk.MultiError 47 48 if d.config.BucketName == "" { 49 errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("the `bucket_name` must be specified")) 50 } 51 if d.config.ChannelName == "" { 52 errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("the `channel_name` must be specified")) 53 } 54 55 if errs != nil && len(errs.Errors) > 0 { 56 return errs 57 } 58 return nil 59 } 60 61 // DatasourceOutput is essentially a copy of []*models.HashicorpCloudPacker20230101Version, but without 62 // the build and ancestry details 63 type DatasourceOutput struct { 64 // Name of the author who created this version. 65 AuthorID string `mapstructure:"author_id"` 66 67 // The name of the bucket that this version is associated with. 68 BucketName string `mapstructure:"bucket_name"` 69 70 // Current state of the version. 71 Status string `mapstructure:"status"` 72 73 // The date the version was created. 74 CreatedAt string `mapstructure:"created_at"` 75 76 // The fingerprint of the version; this is a unique identifier set by the Packer build 77 // that created this version. 78 Fingerprint string `mapstructure:"fingerprint"` 79 80 // The version ID. This is a ULID, which is a unique identifier similar 81 // to a UUID. It is created by the HCP Packer Registry when a version is 82 // first created, and is unique to this version. 83 ID string `mapstructure:"id"` 84 85 // The version name is created by the HCP Packer Registry once a version is 86 // "complete". Incomplete or failed versions currently default to having a name "v0". 87 Name string `mapstructure:"name"` 88 89 // The date when this version was last updated. 90 UpdatedAt string `mapstructure:"updated_at"` 91 92 // The ID of the channel used to query this version. 93 ChannelID string `mapstructure:"channel_id"` 94 } 95 96 func (d *Datasource) OutputSpec() hcldec.ObjectSpec { 97 return (&DatasourceOutput{}).FlatMapstructure().HCL2Spec() 98 } 99 100 func (d *Datasource) Execute() (cty.Value, error) { 101 ctx := context.TODO() 102 103 cli, err := hcpapi.NewClient() 104 if err != nil { 105 return cty.NullVal(cty.EmptyObject), err 106 } 107 log.Printf( 108 "[INFO] Reading HCP Packer Version info from HCP Packer Registry (%s) "+ 109 "[project_id=%s, organization_id=%s, channel=%s]", 110 d.config.BucketName, cli.ProjectID, cli.OrganizationID, d.config.ChannelName, 111 ) 112 113 channel, err := cli.GetChannel(ctx, d.config.BucketName, d.config.ChannelName) 114 if err != nil { 115 return cty.NullVal(cty.EmptyObject), fmt.Errorf( 116 "error retrieving HCP Packer Version from HCP Packer Registry: %s", 117 err.Error(), 118 ) 119 } 120 if channel.Version == nil { 121 return cty.NullVal(cty.EmptyObject), fmt.Errorf( 122 "there is no HCP Packer Version associated with the channel %s", 123 d.config.ChannelName, 124 ) 125 } 126 127 version := channel.Version 128 129 if *version.Status == hcpPackerModels.HashicorpCloudPacker20230101VersionStatusVERSIONREVOKED { 130 return cty.NullVal(cty.EmptyObject), fmt.Errorf( 131 "the HCP Packer Version associated with the channel %s is revoked and can not be used on Packer builds", 132 d.config.ChannelName, 133 ) 134 } 135 136 output := DatasourceOutput{ 137 AuthorID: version.AuthorID, 138 BucketName: version.BucketName, 139 Status: string(*version.Status), 140 CreatedAt: version.CreatedAt.String(), 141 Fingerprint: version.Fingerprint, 142 ID: version.ID, 143 Name: version.Name, 144 UpdatedAt: version.UpdatedAt.String(), 145 ChannelID: channel.ID, 146 } 147 148 return hcl2helper.HCL2ValueFromConfig(output, d.OutputSpec()), nil 149 }