amazon/*: use new interpolation functions

This commit is contained in:
Mitchell Hashimoto 2015-05-27 11:47:45 -07:00
parent 50d7c598e9
commit 034e4e676c
7 changed files with 75 additions and 110 deletions

View File

@ -6,7 +6,6 @@ package chroot
import ( import (
"errors" "errors"
"fmt"
"log" "log"
"runtime" "runtime"
@ -14,7 +13,9 @@ import (
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
awscommon "github.com/mitchellh/packer/builder/amazon/common" awscommon "github.com/mitchellh/packer/builder/amazon/common"
"github.com/mitchellh/packer/common" "github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/helper/config"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
) )
// The unique ID for this builder // The unique ID for this builder
@ -34,7 +35,7 @@ type Config struct {
MountPath string `mapstructure:"mount_path"` MountPath string `mapstructure:"mount_path"`
SourceAmi string `mapstructure:"source_ami"` SourceAmi string `mapstructure:"source_ami"`
tpl *packer.ConfigTemplate ctx *interpolate.Context
} }
type wrappedCommandTemplate struct { type wrappedCommandTemplate struct {
@ -47,18 +48,21 @@ type Builder struct {
} }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
md, err := common.DecodeConfig(&b.config, raws...) b.config.ctx = &interpolate.Context{Funcs: awscommon.TemplateFuncs}
err := config.Decode(&b.config, &config.DecodeOpts{
Interpolate: true,
InterpolateContext: b.config.ctx,
InterpolateFilter: &interpolate.RenderFilter{
Exclude: []string{
"command_wrapper",
"mount_path",
},
},
}, raws...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
b.config.tpl, err = packer.NewConfigTemplate()
if err != nil {
return nil, err
}
b.config.tpl.UserVars = b.config.PackerUserVars
b.config.tpl.Funcs(awscommon.TemplateFuncs)
// Defaults // Defaults
if b.config.ChrootMounts == nil { if b.config.ChrootMounts == nil {
b.config.ChrootMounts = make([][]string, 0) b.config.ChrootMounts = make([][]string, 0)
@ -91,55 +95,22 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
} }
// Accumulate any errors // Accumulate any errors
errs := common.CheckUnusedConfig(md) var errs *packer.MultiError
errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.AMIConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.AMIConfig.Prepare(b.config.ctx)...)
for i, mounts := range b.config.ChrootMounts { for _, mounts := range b.config.ChrootMounts {
if len(mounts) != 3 { if len(mounts) != 3 {
errs = packer.MultiErrorAppend( errs = packer.MultiErrorAppend(
errs, errors.New("Each chroot_mounts entry should be three elements.")) errs, errors.New("Each chroot_mounts entry should be three elements."))
break break
} }
for j, entry := range mounts {
b.config.ChrootMounts[i][j], err = b.config.tpl.Process(entry, nil)
if err != nil {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("Error processing chroot_mounts[%d][%d]: %s",
i, j, err))
}
}
}
for i, file := range b.config.CopyFiles {
var err error
b.config.CopyFiles[i], err = b.config.tpl.Process(file, nil)
if err != nil {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("Error processing copy_files[%d]: %s",
i, err))
}
} }
if b.config.SourceAmi == "" { if b.config.SourceAmi == "" {
errs = packer.MultiErrorAppend(errs, errors.New("source_ami is required.")) errs = packer.MultiErrorAppend(errs, errors.New("source_ami is required."))
} }
templates := map[string]*string{
"device_path": &b.config.DevicePath,
"source_ami": &b.config.SourceAmi,
}
for n, ptr := range templates {
var err error
*ptr, err = b.config.tpl.Process(*ptr, nil)
if err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Error processing %s: %s", n, err))
}
}
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return nil, errs return nil, errs
} }
@ -166,10 +137,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
ec2conn := ec2.New(auth, region) ec2conn := ec2.New(auth, region)
wrappedCommand := func(command string) (string, error) { wrappedCommand := func(command string) (string, error) {
return b.config.tpl.Process( ctx := *b.config.ctx
b.config.CommandWrapper, &wrappedCommandTemplate{ ctx.Data = &wrappedCommandTemplate{Command: command}
Command: command, return interpolate.Render(b.config.CommandWrapper, &ctx)
})
} }
// Setup the state bag and initial state for the steps // Setup the state bag and initial state for the steps

View File

@ -3,12 +3,14 @@ package chroot
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
) )
type mountPathData struct { type mountPathData struct {
@ -31,9 +33,9 @@ func (s *StepMountDevice) Run(state multistep.StateBag) multistep.StepAction {
device := state.Get("device").(string) device := state.Get("device").(string)
wrappedCommand := state.Get("wrappedCommand").(CommandWrapper) wrappedCommand := state.Get("wrappedCommand").(CommandWrapper)
mountPath, err := config.tpl.Process(config.MountPath, &mountPathData{ ctx := *config.ctx
Device: filepath.Base(device), ctx.Data = &mountPathData{Device: filepath.Base(device)}
}) mountPath, err := interpolate.Render(config.MountPath, &ctx)
if err != nil { if err != nil {
err := fmt.Errorf("Error preparing mount directory: %s", err) err := fmt.Errorf("Error preparing mount directory: %s", err)

View File

@ -28,7 +28,6 @@ type Config struct {
awscommon.BlockDevices `mapstructure:",squash"` awscommon.BlockDevices `mapstructure:",squash"`
awscommon.RunConfig `mapstructure:",squash"` awscommon.RunConfig `mapstructure:",squash"`
tpl *packer.ConfigTemplate
ctx *interpolate.Context ctx *interpolate.Context
} }

View File

@ -13,7 +13,9 @@ import (
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
awscommon "github.com/mitchellh/packer/builder/amazon/common" awscommon "github.com/mitchellh/packer/builder/amazon/common"
"github.com/mitchellh/packer/common" "github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/helper/config"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
) )
// The unique ID for this builder // The unique ID for this builder
@ -38,7 +40,7 @@ type Config struct {
X509KeyPath string `mapstructure:"x509_key_path"` X509KeyPath string `mapstructure:"x509_key_path"`
X509UploadPath string `mapstructure:"x509_upload_path"` X509UploadPath string `mapstructure:"x509_upload_path"`
tpl *packer.ConfigTemplate ctx *interpolate.Context
} }
type Builder struct { type Builder struct {
@ -47,18 +49,21 @@ type Builder struct {
} }
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
md, err := common.DecodeConfig(&b.config, raws...) b.config.ctx = &interpolate.Context{Funcs: awscommon.TemplateFuncs}
err := config.Decode(&b.config, &config.DecodeOpts{
Interpolate: true,
InterpolateContext: b.config.ctx,
InterpolateFilter: &interpolate.RenderFilter{
Exclude: []string{
"bundle_upload_command",
"bundle_vol_command",
},
},
}, raws...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
b.config.tpl, err = packer.NewConfigTemplate()
if err != nil {
return nil, err
}
b.config.tpl.UserVars = b.config.PackerUserVars
b.config.tpl.Funcs(awscommon.TemplateFuncs)
if b.config.BundleDestination == "" { if b.config.BundleDestination == "" {
b.config.BundleDestination = "/tmp" b.config.BundleDestination = "/tmp"
} }
@ -97,43 +102,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
} }
// Accumulate any errors // Accumulate any errors
errs := common.CheckUnusedConfig(md) var errs *packer.MultiError
errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.AMIConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.AMIConfig.Prepare(b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.ctx)...)
validates := map[string]*string{
"bundle_upload_command": &b.config.BundleUploadCommand,
"bundle_vol_command": &b.config.BundleVolCommand,
}
for n, ptr := range validates {
if err := b.config.tpl.Validate(*ptr); err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Error parsing %s: %s", n, err))
}
}
templates := map[string]*string{
"account_id": &b.config.AccountId,
"ami_name": &b.config.AMIName,
"bundle_destination": &b.config.BundleDestination,
"bundle_prefix": &b.config.BundlePrefix,
"s3_bucket": &b.config.S3Bucket,
"x509_cert_path": &b.config.X509CertPath,
"x509_key_path": &b.config.X509KeyPath,
"x509_upload_path": &b.config.X509UploadPath,
}
for n, ptr := range templates {
var err error
*ptr, err = b.config.tpl.Process(*ptr, nil)
if err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Error processing %s: %s", n, err))
}
}
if b.config.AccountId == "" { if b.config.AccountId == "" {
errs = packer.MultiErrorAppend(errs, errors.New("account_id is required")) errs = packer.MultiErrorAppend(errs, errors.New("account_id is required"))

View File

@ -6,6 +6,7 @@ import (
"github.com/mitchellh/goamz/ec2" "github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
) )
type bundleCmdData struct { type bundleCmdData struct {
@ -32,7 +33,7 @@ func (s *StepBundleVolume) Run(state multistep.StateBag) multistep.StepAction {
// Bundle the volume // Bundle the volume
var err error var err error
config.BundleVolCommand, err = config.tpl.Process(config.BundleVolCommand, bundleCmdData{ config.ctx.Data = bundleCmdData{
AccountId: config.AccountId, AccountId: config.AccountId,
Architecture: instance.Architecture, Architecture: instance.Architecture,
CertPath: x509RemoteCertPath, CertPath: x509RemoteCertPath,
@ -40,7 +41,8 @@ func (s *StepBundleVolume) Run(state multistep.StateBag) multistep.StepAction {
KeyPath: x509RemoteKeyPath, KeyPath: x509RemoteKeyPath,
Prefix: config.BundlePrefix, Prefix: config.BundlePrefix,
PrivatePath: config.X509UploadPath, PrivatePath: config.X509UploadPath,
}) }
config.BundleVolCommand, err = interpolate.Render(config.BundleVolCommand, config.ctx)
if err != nil { if err != nil {
err := fmt.Errorf("Error processing bundle volume command: %s", err) err := fmt.Errorf("Error processing bundle volume command: %s", err)
state.Put("error", err) state.Put("error", err)

View File

@ -5,6 +5,7 @@ import (
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
) )
type uploadCmdData struct { type uploadCmdData struct {
@ -35,14 +36,15 @@ func (s *StepUploadBundle) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionHalt return multistep.ActionHalt
} }
config.BundleUploadCommand, err = config.tpl.Process(config.BundleUploadCommand, uploadCmdData{ config.ctx.Data = uploadCmdData{
AccessKey: config.AccessKey, AccessKey: config.AccessKey,
BucketName: config.S3Bucket, BucketName: config.S3Bucket,
BundleDirectory: config.BundleDestination, BundleDirectory: config.BundleDestination,
ManifestPath: manifestPath, ManifestPath: manifestPath,
Region: region.Name, Region: region.Name,
SecretKey: config.SecretKey, SecretKey: config.SecretKey,
}) }
config.BundleUploadCommand, err = interpolate.Render(config.BundleUploadCommand, config.ctx)
if err != nil { if err != nil {
err := fmt.Errorf("Error processing bundle upload command: %s", err) err := fmt.Errorf("Error processing bundle upload command: %s", err)
state.Put("error", err) state.Put("error", err)

View File

@ -14,8 +14,10 @@ import (
// doesn't within an interface. // doesn't within an interface.
type RenderFilter struct { type RenderFilter struct {
Include []string Include []string
Exclude []string
once sync.Once once sync.Once
excludeSet map[string]struct{}
includeSet map[string]struct{} includeSet map[string]struct{}
} }
@ -74,9 +76,19 @@ func (f *RenderFilter) include(k string) bool {
return true return true
} }
k = strings.ToLower(k)
f.once.Do(f.init) f.once.Do(f.init)
_, ok := f.includeSet[strings.ToLower(k)] if len(f.includeSet) > 0 {
_, ok := f.includeSet[k]
return ok return ok
}
if len(f.excludeSet) > 0 {
_, ok := f.excludeSet[k]
return !ok
}
return true
} }
func (f *RenderFilter) init() { func (f *RenderFilter) init() {
@ -84,6 +96,11 @@ func (f *RenderFilter) init() {
for _, v := range f.Include { for _, v := range f.Include {
f.includeSet[strings.ToLower(v)] = struct{}{} f.includeSet[strings.ToLower(v)] = struct{}{}
} }
f.excludeSet = make(map[string]struct{})
for _, v := range f.Exclude {
f.excludeSet[strings.ToLower(v)] = struct{}{}
}
} }
// renderWalker implements interfaces for the reflectwalk package // renderWalker implements interfaces for the reflectwalk package