Skip to content

Commit

Permalink
hcp-packer-image: add support for channel
Browse files Browse the repository at this point in the history
In addition to the current way of specifying an image based on an
iteration on HCP Packer, which requires first declaring an iteration,
and then referencing it from the image to build, we add the capacity of
specifying a channel.

This alternative will get the iteration linked to the channel, and is
essentially a more convenient way to get an image's metadata from HCP
Packer.

This commit is essentially a backport from the Terraform HCP provider,
for consistency between the two tools.
  • Loading branch information
lbajolet-hashicorp committed Jul 13, 2022
1 parent 9f64b99 commit fabfc8f
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 8 deletions.
62 changes: 54 additions & 8 deletions datasource/hcp-packer-image/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@ package hcp_packer_image

import (
"context"
"errors"
"fmt"
"log"
"time"

"github.com/zclconf/go-cty/cty"

"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/hcp-sdk-go/clients/cloud-packer-service/stable/2021-04-30/models"
"github.com/hashicorp/packer-plugin-sdk/common"
"github.com/hashicorp/packer-plugin-sdk/hcl2helper"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/template/config"
"github.com/hashicorp/packer/internal/registry"
packerregistry "github.com/hashicorp/packer/internal/registry"
)

Expand All @@ -26,7 +29,19 @@ type Config struct {
common.PackerConfig `mapstructure:",squash"`
// The name of the bucket your image is in.
Bucket string `mapstructure:"bucket_name" required:"true"`
// The name of the channel to use when retrieving your image.
// Either this or `iteration_id` MUST be set.
// Mutually exclusive with `iteration_id`.
// If using several images from a single iteration, you may prefer
// sourcing an iteration first, and referencing it for subsequent uses,
// as every `hcp_packer_image` with the channel set will generate a
// potentially billable HCP Packer request, but if several
// `hcp_packer_image`s use a shared `hcp_packer_iteration` that will
// only generate one potentially billable request.
Channel string `mapstructure:"channel" required:"true"`
// The name of the iteration Id to use when retrieving your image
// Either this or `channel` MUST be set.
// Mutually exclusive with `channel`
IterationID string `mapstructure:"iteration_id" required:"true"`
// The name of the cloud provider that your image is for. For example,
// "aws" or "gce".
Expand All @@ -53,12 +68,19 @@ func (d *Datasource) Configure(raws ...interface{}) error {
if d.config.Bucket == "" {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("The `bucket_name` must be specified"))
}
if d.config.IterationID == "" {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("The `iteration_id`"+
" must be specified. If you do not know your iteration_id, you "+
"can retrieve it using the bucket name and desired channel using"+
" the hcp-packer-iteration data source."))

// Ensure either channel or iteration_id are set, and not both at the same time
if d.config.Channel == "" &&
d.config.IterationID == "" {
errs = packersdk.MultiErrorAppend(errs, errors.New(
"The `iteration_id` or `channel` must be specified."))
}
if d.config.Channel != "" &&
d.config.IterationID != "" {
errs = packersdk.MultiErrorAppend(errs, errors.New(
"`iteration_id` and `channel` cannot both be specified."))
}

if d.config.Region == "" {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("`region` is "+
"currently a required field."))
Expand Down Expand Up @@ -109,6 +131,31 @@ func (d *Datasource) OutputSpec() hcldec.ObjectSpec {
return (&DatasourceOutput{}).FlatMapstructure().HCL2Spec()
}

func (d *Datasource) getIteration(
ctx context.Context,
cli *registry.Client,
) (*models.HashicorpCloudPackerIteration, error) {
if d.config.IterationID != "" {
iter, err := cli.GetIteration(ctx, d.config.Bucket, packerregistry.GetIteration_byID(d.config.IterationID))
if err != nil {
return nil, fmt.Errorf(
"error retrieving image iteration from HCP Packer registry: %s",
err)
}

return iter, nil
}

iter, err := cli.GetIterationFromChannel(ctx, d.config.Bucket, d.config.Channel)
if err != nil {
return nil, fmt.Errorf(
"error retrieving iteration from HCP Packer registry: %s",
err)
}

return iter, nil
}

func (d *Datasource) Execute() (cty.Value, error) {
ctx := context.TODO()

Expand All @@ -121,10 +168,9 @@ func (d *Datasource) Execute() (cty.Value, error) {
log.Printf("[INFO] Reading info from HCP Packer registry (%s) [project_id=%s, organization_id=%s, iteration_id=%s]",
d.config.Bucket, cli.ProjectID, cli.OrganizationID, d.config.IterationID)

iteration, err := cli.GetIteration(ctx, d.config.Bucket, packerregistry.GetIteration_byID(d.config.IterationID))
iteration, err := d.getIteration(ctx, cli)
if err != nil {
return cty.NullVal(cty.EmptyObject), fmt.Errorf("error retrieving "+
"image iteration from HCP Packer registry: %s", err.Error())
return cty.NullVal(cty.EmptyObject), err
}

revokeAt := time.Time(iteration.RevokeAt)
Expand Down
2 changes: 2 additions & 0 deletions datasource/hcp-packer-image/data.hcl2spec.go

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

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,19 @@

- `bucket_name` (string) - The name of the bucket your image is in.

- `channel` (string) - The name of the channel to use when retrieving your image.
Either this or `iteration_id` MUST be set.
Mutually exclusive with `iteration_id`.
If using several images from a single iteration, you may prefer
sourcing an iteration first, and referencing it for subsequent uses,
as every `hcp_packer_image` with the channel set will generate a
potentially billable HCP Packer request, but if several
`hcp_packer_image`s use a shared `hcp_packer_iteration` that will
only generate one potentially billable request.

- `iteration_id` (string) - The name of the iteration Id to use when retrieving your image
Either this or `channel` MUST be set.
Mutually exclusive with `channel`

- `cloud_provider` (string) - The name of the cloud provider that your image is for. For example,
"aws" or "gce".
Expand Down

0 comments on commit fabfc8f

Please sign in to comment.