@ -7,6 +7,7 @@ import (
"io"
"os"
"path/filepath"
"reflect"
"sort"
"strings"
texttemplate "text/template"
@ -14,6 +15,7 @@ import (
"github.com/hashicorp/hcl/v2/hclwrite"
"github.com/hashicorp/packer-plugin-sdk/template"
hcl2shim "github.com/hashicorp/packer/hcl2template/shim"
"github.com/mitchellh/mapstructure"
"github.com/posener/complete"
"github.com/zclconf/go-cty/cty"
)
@ -55,7 +57,7 @@ func (c *HCL2UpgradeCommand) ParseArgs(args []string) (*HCL2UpgradeArgs, int) {
}
const (
hcl2UpgradeFileHeader = ` # This file was autogenerated by the BETA ' packer hcl2_upgrade ' command . We
hcl2UpgradeFileHeader = ` # This file was autogenerated by the ' packer hcl2_upgrade ' command . We
# recommend double checking that everything is correct before going forward . We
# also recommend treating this file as disposable . The HCL2 blocks in this
# file can be moved to other files . For example , the variable blocks could be
@ -91,10 +93,14 @@ const (
# https : //www.packer.io/docs/templates/hcl_templates/blocks/build
build {
`
amazonAmiDataHeader = `
# The amazon - ami data block is generated from your amazon builder source_ami_filter ; a data
# from this block can be referenced in source and locals blocks .
# Read the documentation for data blocks here :
# https : //www.packer.io/docs/templates/hcl_templates/blocks/data`
)
func ( c * HCL2UpgradeCommand ) RunContext ( buildCtx context . Context , cla * HCL2UpgradeArgs ) int {
out := & bytes . Buffer { }
var output io . Writer
if err := os . MkdirAll ( filepath . Dir ( cla . OutputFile ) , 0 ) ; err != nil {
@ -179,11 +185,16 @@ func (c *HCL2UpgradeCommand) RunContext(buildCtx context.Context, cla *HCL2Upgra
for _ , builder := range tpl . Builders {
builders = append ( builders , builder )
}
sort . Slice ( builders , func ( i , j int ) bool {
return builders [ i ] . Type + builders [ i ] . Name < builders [ j ] . Type + builders [ j ] . Name
} )
}
if err := c . writeAmazonAmiDatasource ( builders , out ) ; err != nil {
return 1
}
sort . Slice ( builders , func ( i , j int ) bool {
return builders [ i ] . Type + builders [ i ] . Name < builders [ j ] . Type + builders [ j ] . Name
} )
out . Write ( [ ] byte ( sourcesHeader ) )
for i , builderCfg := range builders {
@ -287,6 +298,61 @@ func (c *HCL2UpgradeCommand) RunContext(buildCtx context.Context, cla *HCL2Upgra
return 0
}
func ( c * HCL2UpgradeCommand ) writeAmazonAmiDatasource ( builders [ ] * template . Builder , out * bytes . Buffer ) error {
amazonAmiFilters := [ ] map [ string ] interface { } { }
first := true
i := 1
for _ , builder := range builders {
if strings . HasPrefix ( builder . Type , "amazon-" ) {
if sourceAmiFilter , ok := builder . Config [ "source_ami_filter" ] ; ok {
sourceAmiFilterCfg := map [ string ] interface { } { }
if err := mapstructure . Decode ( sourceAmiFilter , & sourceAmiFilterCfg ) ; err != nil {
c . Ui . Error ( fmt . Sprintf ( "Failed to write amazon-ami data source: %v" , err ) )
return err
}
duplicate := false
dataSourceName := fmt . Sprintf ( "autogenerated_%d" , i )
for j , filter := range amazonAmiFilters {
if reflect . DeepEqual ( filter , sourceAmiFilter ) {
duplicate = true
dataSourceName = fmt . Sprintf ( "autogenerated_%d" , j + 1 )
continue
}
}
// This is a hack...
// Use templating so that it could be correctly transformed later into a data resource
sourceAmiDataRef := fmt . Sprintf ( "{{ data `amazon-ami.%s.id` }}" , dataSourceName )
if duplicate {
delete ( builder . Config , "source_ami_filter" )
builder . Config [ "source_ami" ] = sourceAmiDataRef
continue
}
amazonAmiFilters = append ( amazonAmiFilters , sourceAmiFilterCfg )
delete ( builder . Config , "source_ami_filter" )
builder . Config [ "source_ami" ] = sourceAmiDataRef
i ++
if first {
out . Write ( [ ] byte ( amazonAmiDataHeader ) )
first = false
}
datasourceContent := hclwrite . NewEmptyFile ( )
body := datasourceContent . Body ( )
body . AppendNewline ( )
sourceBody := body . AppendNewBlock ( "data" , [ ] string { "amazon-ami" , dataSourceName } ) . Body ( )
jsonBodyToHCL2Body ( sourceBody , sourceAmiFilterCfg )
_ , _ = out . Write ( transposeTemplatingCalls ( datasourceContent . Bytes ( ) ) )
}
}
}
return nil
}
type UnhandleableArgumentError struct {
Call string
Correspondance string
@ -327,6 +393,9 @@ func transposeTemplatingCalls(s []byte) []byte {
"build" : func ( a string ) string {
return fmt . Sprintf ( "${build.%s}" , a )
} ,
"data" : func ( a string ) string {
return fmt . Sprintf ( "${data.%s}" , a )
} ,
"template_dir" : func ( ) string {
return fmt . Sprintf ( "${path.root}" )
} ,