Unverified Commit 291121dd authored by Sylvia Moss's avatar Sylvia Moss Committed by GitHub
Browse files

(2) Implement datasources (#10440)

parent ab984090
Showing with 245 additions and 145 deletions
+245 -145
...@@ -12,7 +12,6 @@ import ( ...@@ -12,7 +12,6 @@ import (
"strings" "strings"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer" packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/packer/plugin" "github.com/hashicorp/packer/packer/plugin"
) )
...@@ -130,22 +129,23 @@ func discoverAndLoad() error { ...@@ -130,22 +129,23 @@ func discoverAndLoad() error {
} }
// TODO: validate correctness of plugins loaded by checking them against the output of the `describe` command. // TODO: validate correctness of plugins loaded by checking them against the output of the `describe` command.
builders, provisioners, postProcessors := config.GetPlugins() plugins := config.GetPlugins()
if len(builders) == 0 && if len(plugins.Builders) == 0 &&
len(provisioners) == 0 && len(plugins.Provisioners) == 0 &&
len(postProcessors) == 0 { len(plugins.PostProcessors) == 0 &&
return fmt.Errorf("couldn't load any Builder/Provisioner/Post-Processor from the plugin binary") len(plugins.DataSources) == 0 {
return fmt.Errorf("couldn't load any Builder/Provisioner/Post-Processor/Datasource from the plugin binary")
} }
return checkHCL2ConfigSpec(builders, provisioners, postProcessors) return checkHCL2ConfigSpec(plugins)
} }
// checkHCL2ConfigSpec checks if the hcl2spec config is present for the given plugins by validating that ConfigSpec() does not // checkHCL2ConfigSpec checks if the hcl2spec config is present for the given plugins by validating that ConfigSpec() does not
// return an empty map of specs. // return an empty map of specs.
func checkHCL2ConfigSpec(builders packer.BuilderStore, provisioners packer.ProvisionerStore, postProcessors packer.PostProcessorStore) error { func checkHCL2ConfigSpec(plugins plugin.Plugins) error {
var errs *packersdk.MultiError var errs *packersdk.MultiError
for _, b := range builders.List() { for _, b := range plugins.Builders.List() {
builder, err := builders.Start(b) builder, err := plugins.Builders.Start(b)
if err != nil { if err != nil {
return packersdk.MultiErrorAppend(err, errs) return packersdk.MultiErrorAppend(err, errs)
} }
...@@ -153,8 +153,8 @@ func checkHCL2ConfigSpec(builders packer.BuilderStore, provisioners packer.Provi ...@@ -153,8 +153,8 @@ func checkHCL2ConfigSpec(builders packer.BuilderStore, provisioners packer.Provi
errs = packersdk.MultiErrorAppend(fmt.Errorf("builder %q does not contain the required hcl2spec configuration", b), errs) errs = packersdk.MultiErrorAppend(fmt.Errorf("builder %q does not contain the required hcl2spec configuration", b), errs)
} }
} }
for _, p := range provisioners.List() { for _, p := range plugins.Provisioners.List() {
provisioner, err := provisioners.Start(p) provisioner, err := plugins.Provisioners.Start(p)
if err != nil { if err != nil {
return packersdk.MultiErrorAppend(err, errs) return packersdk.MultiErrorAppend(err, errs)
} }
...@@ -162,8 +162,8 @@ func checkHCL2ConfigSpec(builders packer.BuilderStore, provisioners packer.Provi ...@@ -162,8 +162,8 @@ func checkHCL2ConfigSpec(builders packer.BuilderStore, provisioners packer.Provi
errs = packersdk.MultiErrorAppend(fmt.Errorf("provisioner %q does not contain the required hcl2spec configuration", p), errs) errs = packersdk.MultiErrorAppend(fmt.Errorf("provisioner %q does not contain the required hcl2spec configuration", p), errs)
} }
} }
for _, pp := range postProcessors.List() { for _, pp := range plugins.PostProcessors.List() {
postProcessor, err := postProcessors.Start(pp) postProcessor, err := plugins.PostProcessors.Start(pp)
if err != nil { if err != nil {
return packersdk.MultiErrorAppend(err, errs) return packersdk.MultiErrorAppend(err, errs)
} }
...@@ -171,6 +171,15 @@ func checkHCL2ConfigSpec(builders packer.BuilderStore, provisioners packer.Provi ...@@ -171,6 +171,15 @@ func checkHCL2ConfigSpec(builders packer.BuilderStore, provisioners packer.Provi
errs = packersdk.MultiErrorAppend(fmt.Errorf("post-processor %q does not contain the required hcl2spec configuration", pp), errs) errs = packersdk.MultiErrorAppend(fmt.Errorf("post-processor %q does not contain the required hcl2spec configuration", pp), errs)
} }
} }
for _, d := range plugins.DataSources.List() {
datasource, err := plugins.DataSources.Start(d)
if err != nil {
return packersdk.MultiErrorAppend(err, errs)
}
if len(datasource.ConfigSpec()) == 0 {
errs = packersdk.MultiErrorAppend(fmt.Errorf("datasource %q does not contain the required hcl2spec configuration", d), errs)
}
}
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {
return errs return errs
} }
......
...@@ -70,6 +70,7 @@ func (m *Meta) GetConfigFromHCL(cla *MetaArgs) (*hcl2template.PackerConfig, int) ...@@ -70,6 +70,7 @@ func (m *Meta) GetConfigFromHCL(cla *MetaArgs) (*hcl2template.PackerConfig, int)
BuilderSchemas: m.CoreConfig.Components.BuilderStore, BuilderSchemas: m.CoreConfig.Components.BuilderStore,
ProvisionersSchemas: m.CoreConfig.Components.ProvisionerStore, ProvisionersSchemas: m.CoreConfig.Components.ProvisionerStore,
PostProcessorsSchemas: m.CoreConfig.Components.PostProcessorStore, PostProcessorsSchemas: m.CoreConfig.Components.PostProcessorStore,
DatasourceSchemas: m.CoreConfig.Components.DatasourceStore,
} }
cfg, diags := parser.Parse(cla.Path, cla.VarFiles, cla.Vars) cfg, diags := parser.Parse(cla.Path, cla.VarFiles, cla.Vars)
return cfg, writeDiags(m.Ui, parser.Files(), diags) return cfg, writeDiags(m.Ui, parser.Files(), diags)
...@@ -147,7 +148,7 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, cla *BuildArgs) int ...@@ -147,7 +148,7 @@ func (c *BuildCommand) RunContext(buildCtx context.Context, cla *BuildArgs) int
if ret != 0 { if ret != 0 {
return ret return ret
} }
diags := packerStarter.Initialize() diags := packerStarter.Initialize(packer.InitializeOptions{})
ret = writeDiags(c.Ui, nil, diags) ret = writeDiags(c.Ui, nil, diags)
if ret != 0 { if ret != 0 {
return ret return ret
......
...@@ -371,6 +371,17 @@ func TestBuild(t *testing.T) { ...@@ -371,6 +371,17 @@ func TestBuild(t *testing.T) {
}, },
expectedCode: 1, expectedCode: 1,
}, },
{
name: "hcl - execute and use datasource",
args: []string{
testFixture("hcl", "datasource.pkr.hcl"),
},
fileCheck: fileCheck{
expectedContent: map[string]string{
"chocolate.txt": "chocolate",
},
},
},
} }
for _, tt := range tc { for _, tt := range tc {
...@@ -849,6 +860,9 @@ func testCoreConfigBuilder(t *testing.T) *packer.CoreConfig { ...@@ -849,6 +860,9 @@ func testCoreConfigBuilder(t *testing.T) *packer.CoreConfig {
"shell-local": func() (packersdk.PostProcessor, error) { return &shell_local_pp.PostProcessor{}, nil }, "shell-local": func() (packersdk.PostProcessor, error) { return &shell_local_pp.PostProcessor{}, nil },
"manifest": func() (packersdk.PostProcessor, error) { return &manifest.PostProcessor{}, nil }, "manifest": func() (packersdk.PostProcessor, error) { return &manifest.PostProcessor{}, nil },
}, },
DatasourceStore: packersdk.MapOfDatasource{
"mock": func() (packersdk.Datasource, error) { return &packersdk.MockDatasource{}, nil },
},
} }
return &packer.CoreConfig{ return &packer.CoreConfig{
Components: components, Components: components,
......
...@@ -60,7 +60,7 @@ func (c *ConsoleCommand) RunContext(ctx context.Context, cla *ConsoleArgs) int { ...@@ -60,7 +60,7 @@ func (c *ConsoleCommand) RunContext(ctx context.Context, cla *ConsoleArgs) int {
return ret return ret
} }
_ = packerStarter.Initialize() _ = packerStarter.Initialize(packer.InitializeOptions{})
// Determine if stdin is a pipe. If so, we evaluate directly. // Determine if stdin is a pipe. If so, we evaluate directly.
if c.StdinPiped() { if c.StdinPiped() {
......
...@@ -11,7 +11,7 @@ type CoreWrapper struct { ...@@ -11,7 +11,7 @@ type CoreWrapper struct {
*packer.Core *packer.Core
} }
func (c *CoreWrapper) Initialize() hcl.Diagnostics { func (c *CoreWrapper) Initialize(_ packer.InitializeOptions) hcl.Diagnostics {
err := c.Core.Initialize() err := c.Core.Initialize()
if err != nil { if err != nil {
return hcl.Diagnostics{ return hcl.Diagnostics{
......
...@@ -13,8 +13,8 @@ import ( ...@@ -13,8 +13,8 @@ import (
texttemplate "text/template" texttemplate "text/template"
"github.com/hashicorp/hcl/v2/hclwrite" "github.com/hashicorp/hcl/v2/hclwrite"
hcl2shim "github.com/hashicorp/packer-plugin-sdk/hcl2helper"
"github.com/hashicorp/packer-plugin-sdk/template" "github.com/hashicorp/packer-plugin-sdk/template"
hcl2shim "github.com/hashicorp/packer/hcl2template/shim"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/posener/complete" "github.com/posener/complete"
"github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty"
......
...@@ -46,7 +46,7 @@ func (c *InspectCommand) RunContext(ctx context.Context, cla *InspectArgs) int { ...@@ -46,7 +46,7 @@ func (c *InspectCommand) RunContext(ctx context.Context, cla *InspectArgs) int {
} }
// here we ignore init diags to allow unknown variables to be used // here we ignore init diags to allow unknown variables to be used
_ = packerStarter.Initialize() _ = packerStarter.Initialize(packer.InitializeOptions{})
return packerStarter.InspectConfig(packer.InspectConfigOptions{ return packerStarter.InspectConfig(packer.InspectConfigOptions{
Ui: c.Ui, Ui: c.Ui,
......
...@@ -212,7 +212,9 @@ var PostProcessors = map[string]packersdk.PostProcessor{ ...@@ -212,7 +212,9 @@ var PostProcessors = map[string]packersdk.PostProcessor{
"yandex-import": new(yandeximportpostprocessor.PostProcessor), "yandex-import": new(yandeximportpostprocessor.PostProcessor),
} }
var pluginRegexp = regexp.MustCompile("packer-(builder|post-processor|provisioner)-(.+)") var Datasources = map[string]packersdk.Datasource{}
var pluginRegexp = regexp.MustCompile("packer-(builder|post-processor|provisioner|datasource)-(.+)")
func (c *PluginCommand) Run(args []string) int { func (c *PluginCommand) Run(args []string) int {
// This is an internal call (users should not call this directly) so we're // This is an internal call (users should not call this directly) so we're
...@@ -261,6 +263,13 @@ func (c *PluginCommand) Run(args []string) int { ...@@ -261,6 +263,13 @@ func (c *PluginCommand) Run(args []string) int {
return 1 return 1
} }
server.RegisterPostProcessor(postProcessor) server.RegisterPostProcessor(postProcessor)
case "datasource":
datasource, found := Datasources[pluginName]
if !found {
c.Ui.Error(fmt.Sprintf("Could not load datasource: %s", pluginName))
return 1
}
server.RegisterDatasource(datasource)
} }
server.Serve() server.Serve()
......
data "mock" "content" {
foo = "chocolate"
}
source "file" "chocolate" {
content = data.mock.content.foo
target = "chocolate.txt"
}
build {
sources = [
"sources.file.chocolate",
]
}
packer {
required_version = ">= v1.0.0"
}
data "mock" "content" {
foo = "content"
}
source "file" "chocolate" {
target = "chocolate.txt"
content = data.mock.content.foo
}
build {
sources = ["source.file.chocolate"]
}
...@@ -56,7 +56,9 @@ func (c *ValidateCommand) RunContext(ctx context.Context, cla *ValidateArgs) int ...@@ -56,7 +56,9 @@ func (c *ValidateCommand) RunContext(ctx context.Context, cla *ValidateArgs) int
return 0 return 0
} }
diags := packerStarter.Initialize() diags := packerStarter.Initialize(packer.InitializeOptions{
SkipDatasourcesExecution: true,
})
ret = writeDiags(c.Ui, nil, diags) ret = writeDiags(c.Ui, nil, diags)
if ret != 0 { if ret != 0 {
return ret return ret
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"testing" "testing"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
) )
func TestValidateCommand(t *testing.T) { func TestValidateCommand(t *testing.T) {
...@@ -45,6 +46,29 @@ func TestValidateCommand(t *testing.T) { ...@@ -45,6 +46,29 @@ func TestValidateCommand(t *testing.T) {
} }
} }
func TestValidateCommand_SkipDatasourceExecution(t *testing.T) {
datasourceMock := &packersdk.MockDatasource{}
meta := testMetaFile(t)
meta.CoreConfig.Components.DatasourceStore = packersdk.MapOfDatasource{
"mock": func() (packersdk.Datasource, error) {
return datasourceMock, nil
},
}
c := &ValidateCommand{
Meta: meta,
}
args := []string{filepath.Join(testFixture("validate"), "datasource.pkr.hcl")}
if code := c.Run(args); code != 0 {
fatalCommand(t, c.Meta)
}
if datasourceMock.ExecuteCalled {
t.Fatalf("Datasource should not be executed on validation")
}
if !datasourceMock.OutputSpecCalled {
t.Fatalf("Datasource OutPutSpec should be called on validation")
}
}
func TestValidateCommand_SyntaxOnly(t *testing.T) { func TestValidateCommand_SyntaxOnly(t *testing.T) {
tt := []struct { tt := []struct {
path string path string
......
...@@ -30,6 +30,7 @@ type config struct { ...@@ -30,6 +30,7 @@ type config struct {
Builders packer.MapOfBuilder `json:"-"` Builders packer.MapOfBuilder `json:"-"`
Provisioners packer.MapOfProvisioner `json:"-"` Provisioners packer.MapOfProvisioner `json:"-"`
PostProcessors packer.MapOfPostProcessor `json:"-"` PostProcessors packer.MapOfPostProcessor `json:"-"`
Datasources packer.MapOfDatasource `json:"-"`
Plugins plugin.Config Plugins plugin.Config
} }
...@@ -186,5 +187,17 @@ func (c *config) discoverInternalComponents() error { ...@@ -186,5 +187,17 @@ func (c *config) discoverInternalComponents() error {
} }
} }
for dataSource := range command.Datasources {
dataSource := dataSource
_, found := (c.Datasources)[dataSource]
if !found {
c.Datasources[dataSource] = func() (packersdk.Datasource, error) {
bin := fmt.Sprintf("%s%splugin%spacker-datasource-%s",
packerPath, PACKERSPACE, PACKERSPACE, dataSource)
return c.Plugins.Client(bin).Datasource()
}
}
}
return nil return nil
} }
This diff is collapsed.
...@@ -33,6 +33,9 @@ func getBasicParser() *Parser { ...@@ -33,6 +33,9 @@ func getBasicParser() *Parser {
"amazon-import": func() (packersdk.PostProcessor, error) { return &MockPostProcessor{}, nil }, "amazon-import": func() (packersdk.PostProcessor, error) { return &MockPostProcessor{}, nil },
"manifest": func() (packersdk.PostProcessor, error) { return &MockPostProcessor{}, nil }, "manifest": func() (packersdk.PostProcessor, error) { return &MockPostProcessor{}, nil },
}, },
DatasourceSchemas: packersdk.MapOfDatasource{
"amazon-ami": func() (packersdk.Datasource, error) { return &MockDatasource{}, nil },
},
} }
} }
...@@ -62,7 +65,7 @@ func testParse(t *testing.T, tests []parseTest) { ...@@ -62,7 +65,7 @@ func testParse(t *testing.T, tests []parseTest) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
gotCfg, gotDiags := tt.parser.Parse(tt.args.filename, tt.args.varFiles, tt.args.vars) gotCfg, gotDiags := tt.parser.Parse(tt.args.filename, tt.args.varFiles, tt.args.vars)
moreDiags := gotCfg.Initialize() moreDiags := gotCfg.Initialize(packer.InitializeOptions{})
gotDiags = append(gotDiags, moreDiags...) gotDiags = append(gotDiags, moreDiags...)
if tt.parseWantDiags == (gotDiags == nil) { if tt.parseWantDiags == (gotDiags == nil) {
t.Fatalf("Parser.parse() unexpected %q diagnostics.", gotDiags) t.Fatalf("Parser.parse() unexpected %q diagnostics.", gotDiags)
...@@ -125,13 +128,39 @@ var ( ...@@ -125,13 +128,39 @@ var (
Tags: []MockTag{}, Tags: []MockTag{},
} }
// everything in the tests is a basicNestedMockConfig this allow to test
// each known type to packer ( and embedding ) in one go.
builderBasicNestedMockConfig = NestedMockConfig{
String: "string",
Int: 42,
Int64: 43,
Bool: true,
Trilean: config.TriTrue,
Duration: 10 * time.Second,
MapStringString: map[string]string{
"a": "b",
"c": "d",
},
SliceString: []string{
"a",
"b",
"c",
},
SliceSliceString: [][]string{
{"a", "b"},
{"c", "d"},
},
Tags: []MockTag{},
Datasource: "string",
}
basicMockBuilder = &MockBuilder{ basicMockBuilder = &MockBuilder{
Config: MockConfig{ Config: MockConfig{
NestedMockConfig: basicNestedMockConfig, NestedMockConfig: builderBasicNestedMockConfig,
Nested: basicNestedMockConfig, Nested: builderBasicNestedMockConfig,
NestedSlice: []NestedMockConfig{ NestedSlice: []NestedMockConfig{
basicNestedMockConfig, builderBasicNestedMockConfig,
basicNestedMockConfig, builderBasicNestedMockConfig,
}, },
}, },
} }
...@@ -226,6 +255,7 @@ var cmpOpts = []cmp.Option{ ...@@ -226,6 +255,7 @@ var cmpOpts = []cmp.Option{
PackerConfig{}, PackerConfig{},
Variable{}, Variable{},
SourceBlock{}, SourceBlock{},
Datasource{},
ProvisionerBlock{}, ProvisionerBlock{},
PostProcessorBlock{}, PostProcessorBlock{},
packer.CoreBuild{}, packer.CoreBuild{},
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"time" "time"
"github.com/hashicorp/hcl/v2/hcldec" "github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer-plugin-sdk/hcl2helper"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer" packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/template/config" "github.com/hashicorp/packer-plugin-sdk/template/config"
"github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty"
...@@ -26,6 +27,7 @@ type NestedMockConfig struct { ...@@ -26,6 +27,7 @@ type NestedMockConfig struct {
NamedMapStringString NamedMapStringString `mapstructure:"named_map_string_string"` NamedMapStringString NamedMapStringString `mapstructure:"named_map_string_string"`
NamedString NamedString `mapstructure:"named_string"` NamedString NamedString `mapstructure:"named_string"`
Tags []MockTag `mapstructure:"tag"` Tags []MockTag `mapstructure:"tag"`
Datasource string `mapstructure:"data_source"`
} }
type MockTag struct { type MockTag struct {
...@@ -103,6 +105,32 @@ func (b *MockProvisioner) Provision(ctx context.Context, ui packersdk.Ui, comm p ...@@ -103,6 +105,32 @@ func (b *MockProvisioner) Provision(ctx context.Context, ui packersdk.Ui, comm p
return nil return nil
} }
//////
// MockDatasource
//////
type MockDatasource struct {
Config MockConfig
}
var _ packersdk.Datasource = new(MockDatasource)
func (d *MockDatasource) ConfigSpec() hcldec.ObjectSpec {
return d.Config.FlatMapstructure().HCL2Spec()
}
func (d *MockDatasource) OutputSpec() hcldec.ObjectSpec {
return d.Config.FlatMapstructure().HCL2Spec()
}
func (d *MockDatasource) Configure(raws ...interface{}) error {
return d.Config.Prepare(raws...)
}
func (d *MockDatasource) Execute() (cty.Value, error) {
return hcl2helper.HCL2ValueFromConfig(d.Config, d.OutputSpec()), nil
}
////// //////
// MockPostProcessor // MockPostProcessor
////// //////
......
...@@ -23,6 +23,7 @@ type FlatMockConfig struct { ...@@ -23,6 +23,7 @@ type FlatMockConfig struct {
NamedMapStringString NamedMapStringString `mapstructure:"named_map_string_string" cty:"named_map_string_string" hcl:"named_map_string_string"` NamedMapStringString NamedMapStringString `mapstructure:"named_map_string_string" cty:"named_map_string_string" hcl:"named_map_string_string"`
NamedString *NamedString `mapstructure:"named_string" cty:"named_string" hcl:"named_string"` NamedString *NamedString `mapstructure:"named_string" cty:"named_string" hcl:"named_string"`
Tags []FlatMockTag `mapstructure:"tag" cty:"tag" hcl:"tag"` Tags []FlatMockTag `mapstructure:"tag" cty:"tag" hcl:"tag"`
Datasource *string `mapstructure:"data_source" cty:"data_source" hcl:"data_source"`
Nested *FlatNestedMockConfig `mapstructure:"nested" cty:"nested" hcl:"nested"` Nested *FlatNestedMockConfig `mapstructure:"nested" cty:"nested" hcl:"nested"`
NestedSlice []FlatNestedMockConfig `mapstructure:"nested_slice" cty:"nested_slice" hcl:"nested_slice"` NestedSlice []FlatNestedMockConfig `mapstructure:"nested_slice" cty:"nested_slice" hcl:"nested_slice"`
} }
...@@ -52,6 +53,7 @@ func (*FlatMockConfig) HCL2Spec() map[string]hcldec.Spec { ...@@ -52,6 +53,7 @@ func (*FlatMockConfig) HCL2Spec() map[string]hcldec.Spec {
"named_map_string_string": &hcldec.AttrSpec{Name: "named_map_string_string", Type: cty.Map(cty.String), Required: false}, "named_map_string_string": &hcldec.AttrSpec{Name: "named_map_string_string", Type: cty.Map(cty.String), Required: false},
"named_string": &hcldec.AttrSpec{Name: "named_string", Type: cty.String, Required: false}, "named_string": &hcldec.AttrSpec{Name: "named_string", Type: cty.String, Required: false},
"tag": &hcldec.BlockListSpec{TypeName: "tag", Nested: hcldec.ObjectSpec((*FlatMockTag)(nil).HCL2Spec())}, "tag": &hcldec.BlockListSpec{TypeName: "tag", Nested: hcldec.ObjectSpec((*FlatMockTag)(nil).HCL2Spec())},
"data_source": &hcldec.AttrSpec{Name: "data_source", Type: cty.String, Required: false},
"nested": &hcldec.BlockSpec{TypeName: "nested", Nested: hcldec.ObjectSpec((*FlatNestedMockConfig)(nil).HCL2Spec())}, "nested": &hcldec.BlockSpec{TypeName: "nested", Nested: hcldec.ObjectSpec((*FlatNestedMockConfig)(nil).HCL2Spec())},
"nested_slice": &hcldec.BlockListSpec{TypeName: "nested_slice", Nested: hcldec.ObjectSpec((*FlatNestedMockConfig)(nil).HCL2Spec())}, "nested_slice": &hcldec.BlockListSpec{TypeName: "nested_slice", Nested: hcldec.ObjectSpec((*FlatNestedMockConfig)(nil).HCL2Spec())},
} }
...@@ -98,6 +100,7 @@ type FlatNestedMockConfig struct { ...@@ -98,6 +100,7 @@ type FlatNestedMockConfig struct {
NamedMapStringString NamedMapStringString `mapstructure:"named_map_string_string" cty:"named_map_string_string" hcl:"named_map_string_string"` NamedMapStringString NamedMapStringString `mapstructure:"named_map_string_string" cty:"named_map_string_string" hcl:"named_map_string_string"`
NamedString *NamedString `mapstructure:"named_string" cty:"named_string" hcl:"named_string"` NamedString *NamedString `mapstructure:"named_string" cty:"named_string" hcl:"named_string"`
Tags []FlatMockTag `mapstructure:"tag" cty:"tag" hcl:"tag"` Tags []FlatMockTag `mapstructure:"tag" cty:"tag" hcl:"tag"`
Datasource *string `mapstructure:"data_source" cty:"data_source" hcl:"data_source"`
} }
// FlatMapstructure returns a new FlatNestedMockConfig. // FlatMapstructure returns a new FlatNestedMockConfig.
...@@ -124,6 +127,7 @@ func (*FlatNestedMockConfig) HCL2Spec() map[string]hcldec.Spec { ...@@ -124,6 +127,7 @@ func (*FlatNestedMockConfig) HCL2Spec() map[string]hcldec.Spec {
"named_map_string_string": &hcldec.AttrSpec{Name: "named_map_string_string", Type: cty.Map(cty.String), Required: false}, "named_map_string_string": &hcldec.AttrSpec{Name: "named_map_string_string", Type: cty.Map(cty.String), Required: false},
"named_string": &hcldec.AttrSpec{Name: "named_string", Type: cty.String, Required: false}, "named_string": &hcldec.AttrSpec{Name: "named_string", Type: cty.String, Required: false},
"tag": &hcldec.BlockListSpec{TypeName: "tag", Nested: hcldec.ObjectSpec((*FlatMockTag)(nil).HCL2Spec())}, "tag": &hcldec.BlockListSpec{TypeName: "tag", Nested: hcldec.ObjectSpec((*FlatMockTag)(nil).HCL2Spec())},
"data_source": &hcldec.AttrSpec{Name: "data_source", Type: cty.String, Required: false},
} }
return s return s
} }
...@@ -20,6 +20,7 @@ const ( ...@@ -20,6 +20,7 @@ const (
variablesLabel = "variables" variablesLabel = "variables"
variableLabel = "variable" variableLabel = "variable"
localsLabel = "locals" localsLabel = "locals"
dataSourceLabel = "data"
buildLabel = "build" buildLabel = "build"
communicatorLabel = "communicator" communicatorLabel = "communicator"
) )
...@@ -31,6 +32,7 @@ var configSchema = &hcl.BodySchema{ ...@@ -31,6 +32,7 @@ var configSchema = &hcl.BodySchema{
{Type: variablesLabel}, {Type: variablesLabel},
{Type: variableLabel, LabelNames: []string{"name"}}, {Type: variableLabel, LabelNames: []string{"name"}},
{Type: localsLabel}, {Type: localsLabel},
{Type: dataSourceLabel, LabelNames: []string{"type", "name"}},
{Type: buildLabel}, {Type: buildLabel},
{Type: communicatorLabel, LabelNames: []string{"type", "name"}}, {Type: communicatorLabel, LabelNames: []string{"type", "name"}},
}, },
...@@ -60,6 +62,8 @@ type Parser struct { ...@@ -60,6 +62,8 @@ type Parser struct {
ProvisionersSchemas packer.ProvisionerStore ProvisionersSchemas packer.ProvisionerStore
PostProcessorsSchemas packer.PostProcessorStore PostProcessorsSchemas packer.PostProcessorStore
DatasourceSchemas packer.DatasourceStore
} }
const ( const (
...@@ -129,6 +133,7 @@ func (p *Parser) Parse(filename string, varFiles []string, argVars map[string]st ...@@ -129,6 +133,7 @@ func (p *Parser) Parse(filename string, varFiles []string, argVars map[string]st
builderSchemas: p.BuilderSchemas, builderSchemas: p.BuilderSchemas,
provisionersSchemas: p.ProvisionersSchemas, provisionersSchemas: p.ProvisionersSchemas,
postProcessorsSchemas: p.PostProcessorsSchemas, postProcessorsSchemas: p.PostProcessorsSchemas,
datasourceSchemas: p.DatasourceSchemas,
parser: p, parser: p,
files: files, files: files,
} }
...@@ -155,6 +160,11 @@ func (p *Parser) Parse(filename string, varFiles []string, argVars map[string]st ...@@ -155,6 +160,11 @@ func (p *Parser) Parse(filename string, varFiles []string, argVars map[string]st
diags = append(diags, cfg.decodeInputVariables(file)...) diags = append(diags, cfg.decodeInputVariables(file)...)
} }
for _, file := range files {
morediags := p.decodeDatasources(file, cfg)
diags = append(diags, morediags...)
}
for _, file := range files { for _, file := range files {
moreLocals, morediags := cfg.parseLocalVariables(file) moreLocals, morediags := cfg.parseLocalVariables(file)
diags = append(diags, morediags...) diags = append(diags, morediags...)
...@@ -247,13 +257,14 @@ func sniffCoreVersionRequirements(body hcl.Body) ([]VersionConstraint, hcl.Diagn ...@@ -247,13 +257,14 @@ func sniffCoreVersionRequirements(body hcl.Body) ([]VersionConstraint, hcl.Diagn
return constraints, diags return constraints, diags
} }
func (cfg *PackerConfig) Initialize() hcl.Diagnostics { func (cfg *PackerConfig) Initialize(opts packer.InitializeOptions) hcl.Diagnostics {
var diags hcl.Diagnostics var diags hcl.Diagnostics
_, moreDiags := cfg.InputVariables.Values() _, moreDiags := cfg.InputVariables.Values()
diags = append(diags, moreDiags...) diags = append(diags, moreDiags...)
_, moreDiags = cfg.LocalVariables.Values() _, moreDiags = cfg.LocalVariables.Values()
diags = append(diags, moreDiags...) diags = append(diags, moreDiags...)
diags = append(diags, cfg.evaluateDatasources(opts.SkipDatasourcesExecution)...)
diags = append(diags, cfg.evaluateLocalVariables(cfg.LocalBlocks)...) diags = append(diags, cfg.evaluateLocalVariables(cfg.LocalBlocks)...)
for _, variable := range cfg.InputVariables { for _, variable := range cfg.InputVariables {
...@@ -328,3 +339,41 @@ func (p *Parser) decodeConfig(f *hcl.File, cfg *PackerConfig) hcl.Diagnostics { ...@@ -328,3 +339,41 @@ func (p *Parser) decodeConfig(f *hcl.File, cfg *PackerConfig) hcl.Diagnostics {
return diags return diags
} }
func (p *Parser) decodeDatasources(file *hcl.File, cfg *PackerConfig) hcl.Diagnostics {
var diags hcl.Diagnostics
body := dynblock.Expand(file.Body, cfg.EvalContext(nil))
content, moreDiags := body.Content(configSchema)
diags = append(diags, moreDiags...)
for _, block := range content.Blocks {
switch block.Type {
case dataSourceLabel:
datasource, moreDiags := p.decodeDataBlock(block)
diags = append(diags, moreDiags...)
if moreDiags.HasErrors() {
continue
}
ref := datasource.Ref()
if existing, found := cfg.Datasources[ref]; found {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Duplicate " + dataSourceLabel + " block",
Detail: fmt.Sprintf("This "+dataSourceLabel+" block has the "+
"same data type and name as a previous block declared "+
"at %s. Each "+dataSourceLabel+" must have a unique name per builder type.",
existing.block.DefRange.Ptr()),
Subject: datasource.block.DefRange.Ptr(),
})
continue
}
if cfg.Datasources == nil {
cfg.Datasources = Datasources{}
}
cfg.Datasources[ref] = *datasource
}
}
return diags
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment