mirror of
https://github.com/hashicorp/packer.git
synced 2026-06-25 08:28:59 -04:00
* Updating the license from MPL to Business Source License Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at https://hashi.co/bsl-blog, FAQ at https://hashi.co/license-faq, and details of the license at www.hashicorp.com/bsl. * Update copyright file headers to BUSL-1.1 --------- Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
146 lines
5.3 KiB
Go
146 lines
5.3 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
//go:generate packer-sdc struct-markdown
|
|
//go:generate packer-sdc mapstructure-to-hcl2 -type DatasourceOutput,Config
|
|
package hcp_packer_iteration
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
"github.com/hashicorp/hcl/v2/hcldec"
|
|
"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"
|
|
hcpapi "github.com/hashicorp/packer/internal/hcp/api"
|
|
)
|
|
|
|
type Datasource struct {
|
|
config Config
|
|
}
|
|
|
|
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
|
|
Channel string `mapstructure:"channel" required:"true"`
|
|
// TODO: Version string `mapstructure:"version"`
|
|
// TODO: Fingerprint string `mapstructure:"fingerprint"`
|
|
// TODO: Label string `mapstructure:"label"`
|
|
}
|
|
|
|
func (d *Datasource) ConfigSpec() hcldec.ObjectSpec {
|
|
return d.config.FlatMapstructure().HCL2Spec()
|
|
}
|
|
|
|
func (d *Datasource) Configure(raws ...interface{}) error {
|
|
err := config.Decode(&d.config, nil, raws...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var errs *packersdk.MultiError
|
|
|
|
if d.config.Bucket == "" {
|
|
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("The `bucket_name` must be specified"))
|
|
}
|
|
if d.config.Channel == "" {
|
|
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("`channel` is currently a required field."))
|
|
}
|
|
|
|
if errs != nil && len(errs.Errors) > 0 {
|
|
return errs
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DatasourceOutput is essentially a copy of []*models.HashicorpCloudPackerIteration, but without the
|
|
// []Builds or ancestor id.
|
|
type DatasourceOutput struct {
|
|
// who created the iteration
|
|
AuthorID string `mapstructure:"author_id"`
|
|
// Name of the bucket that the iteration was retrieved from
|
|
BucketName string `mapstructure:"bucket_name"`
|
|
// If true, this iteration is considered "ready to use" and will be
|
|
// returned even if the include_incomplete flag is "false" in the
|
|
// list iterations request. Note that if you are retrieving an iteration
|
|
// using a channel, this will always be "true"; channels cannot be assigned
|
|
// to incomplete iterations.
|
|
Complete bool `mapstructure:"complete"`
|
|
// The date the iteration was created.
|
|
CreatedAt string `mapstructure:"created_at"`
|
|
// The fingerprint of the build; this could be a git sha or other unique
|
|
// identifier as set by the Packer build that created this iteration.
|
|
Fingerprint string `mapstructure:"fingerprint"`
|
|
// The iteration ID. This is a ULID, which is a unique identifier similar
|
|
// to a UUID. It is created by the HCP Packer Registry when an iteration is
|
|
// first created, and is unique to this iteration.
|
|
ID string `mapstructure:"id"`
|
|
// The version number assigned to an iteration. This number is an integer,
|
|
// and is created by the HCP Packer Registry once an iteration is
|
|
// marked "complete". If a new iteration is marked "complete", the version
|
|
// that HCP Packer assigns to it will always be the highest previous
|
|
// iteration version plus one.
|
|
IncrementalVersion int32 `mapstructure:"incremental_version"`
|
|
// The date when this iteration was last updated.
|
|
UpdatedAt string `mapstructure:"updated_at"`
|
|
// The ID of the channel used to query the image iteration.
|
|
ChannelID string `mapstructure:"channel_id"`
|
|
}
|
|
|
|
func (d *Datasource) OutputSpec() hcldec.ObjectSpec {
|
|
return (&DatasourceOutput{}).FlatMapstructure().HCL2Spec()
|
|
}
|
|
|
|
func (d *Datasource) Execute() (cty.Value, error) {
|
|
ctx := context.TODO()
|
|
|
|
cli, err := hcpapi.NewClient()
|
|
if err != nil {
|
|
return cty.NullVal(cty.EmptyObject), err
|
|
}
|
|
// Load channel.
|
|
log.Printf("[INFO] Reading iteration info from HCP Packer registry (%s) [project_id=%s, organization_id=%s, channel=%s]",
|
|
d.config.Bucket, cli.ProjectID, cli.OrganizationID, d.config.Channel)
|
|
|
|
channel, err := cli.GetChannel(ctx, d.config.Bucket, d.config.Channel)
|
|
if err != nil {
|
|
return cty.NullVal(cty.EmptyObject), fmt.Errorf("error retrieving "+
|
|
"iteration from HCP Packer registry: %s", err.Error())
|
|
}
|
|
if channel.Iteration == nil {
|
|
return cty.NullVal(cty.EmptyObject), fmt.Errorf("there is no iteration associated with the channel %s",
|
|
d.config.Channel)
|
|
}
|
|
|
|
iteration := channel.Iteration
|
|
|
|
revokeAt := time.Time(iteration.RevokeAt)
|
|
if !revokeAt.IsZero() && revokeAt.Before(time.Now().UTC()) {
|
|
// If RevokeAt is not a zero date and is before NOW, it means this iteration is revoked and should not be used
|
|
// to build new images.
|
|
return cty.NullVal(cty.EmptyObject), fmt.Errorf("the iteration associated with the channel %s is revoked and can not be used on Packer builds",
|
|
d.config.Channel)
|
|
}
|
|
|
|
output := DatasourceOutput{
|
|
AuthorID: iteration.AuthorID,
|
|
BucketName: iteration.BucketSlug,
|
|
Complete: iteration.Complete,
|
|
CreatedAt: iteration.CreatedAt.String(),
|
|
Fingerprint: iteration.Fingerprint,
|
|
ID: iteration.ID,
|
|
IncrementalVersion: iteration.IncrementalVersion,
|
|
UpdatedAt: iteration.UpdatedAt.String(),
|
|
ChannelID: channel.ID,
|
|
}
|
|
|
|
return hcl2helper.HCL2ValueFromConfig(output, d.OutputSpec()), nil
|
|
}
|