diff --git a/go.mod b/go.mod index 3a76dcfec..13e7c273b 100644 --- a/go.mod +++ b/go.mod @@ -59,6 +59,7 @@ require ( github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de github.com/hashicorp/go-cleanhttp v0.5.1 github.com/hashicorp/go-cty-funcs v0.0.0-20200520133146-0d04eb807361 + github.com/hashicorp/go-getter v1.4.1 github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200604122502-a6995fa1edad github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200604122502-a6995fa1edad github.com/hashicorp/go-getter/v2 v2.0.0-20200604122502-a6995fa1edad diff --git a/provisioner/salt-masterless/provisioner.go b/provisioner/salt-masterless/provisioner.go index de64b27a2..d89d325ff 100644 --- a/provisioner/salt-masterless/provisioner.go +++ b/provisioner/salt-masterless/provisioner.go @@ -13,6 +13,7 @@ import ( "path/filepath" "strings" + "github.com/hashicorp/go-getter" "github.com/hashicorp/hcl/v2/hcldec" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/config" @@ -72,6 +73,9 @@ type Config struct { // The Guest OS Type (unix or windows) GuestOSType string `mapstructure:"guest_os_type"` + // An array of private or community git source formulas + Formulas []string `mapstructure:"formulas"` + ctx interpolate.Context } @@ -228,6 +232,31 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.Communicator, _ map[string]interface{}) error { var err error var src, dst string + var formulas []string + + if p.config.Formulas != nil && len(p.config.Formulas) > 0 { + ui.Say("Downloading Salt formulas...") + client := new(getter.Client) + for _, i := range p.config.Formulas { + client.Src = i + // Use //subdirectory name when creating in local_state_tree directory + state := strings.Split(i, "//") + last := state[len(state)-1] + path := filepath.Join(p.config.LocalStateTree, last) + formulas = append(formulas, path) + if _, err := os.Stat(path); os.IsNotExist(err) { + ui.Message(fmt.Sprintf("%s => %s", i, path)) + if err = os.Mkdir(path, 0755); err != nil { + return fmt.Errorf("Unable to create Salt state directory: %s", err) + } + client.Dst = path + client.Mode = getter.ClientModeAny + if err = client.Get(); err != nil { + return fmt.Errorf("Unable to download Salt formula from %s: %s", i, err) + } + } + } + } ui.Say("Provisioning with Salt...") if !p.config.SkipBootstrap { @@ -318,6 +347,16 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C return fmt.Errorf("Unable to move %s/states to %s: %s", p.config.TempConfigDir, dst, err) } + // Remove the local Salt formulas if present + if p.config.Formulas != nil { + for _, f := range formulas { + if _, err := os.Stat(f); !os.IsNotExist(err) { + ui.Message(fmt.Sprintf("Removing Salt formula: %s", f)) + os.RemoveAll(f) + } + } + } + if p.config.LocalPillarRoots != "" { ui.Message(fmt.Sprintf("Uploading local pillar roots: %s", p.config.LocalPillarRoots)) src = p.config.LocalPillarRoots diff --git a/provisioner/salt-masterless/provisioner.hcl2spec.go b/provisioner/salt-masterless/provisioner.hcl2spec.go index ee63a810c..29e9b23cb 100644 --- a/provisioner/salt-masterless/provisioner.hcl2spec.go +++ b/provisioner/salt-masterless/provisioner.hcl2spec.go @@ -32,6 +32,7 @@ type FlatConfig struct { SaltCallArgs *string `mapstructure:"salt_call_args" cty:"salt_call_args" hcl:"salt_call_args"` SaltBinDir *string `mapstructure:"salt_bin_dir" cty:"salt_bin_dir" hcl:"salt_bin_dir"` GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type" hcl:"guest_os_type"` + Formulas []string `mapstructure:"formulas" cty:"formulas" hcl:"formulas"` } // FlatMapstructure returns a new FlatConfig. @@ -69,6 +70,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "salt_call_args": &hcldec.AttrSpec{Name: "salt_call_args", Type: cty.String, Required: false}, "salt_bin_dir": &hcldec.AttrSpec{Name: "salt_bin_dir", Type: cty.String, Required: false}, "guest_os_type": &hcldec.AttrSpec{Name: "guest_os_type", Type: cty.String, Required: false}, + "formulas": &hcldec.AttrSpec{Name: "formulas", Type: cty.List(cty.String), Required: false}, } return s }