file provisioner: add possibility to set content + tests (#11209)

pull/11224/head
Adrien Delorme 5 years ago committed by GitHub
parent 57f37c99ea
commit 1d915adad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -17,10 +17,18 @@ import (
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/template/config"
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
"github.com/hashicorp/packer-plugin-sdk/tmp"
)
type Config struct {
common.PackerConfig `mapstructure:",squash"`
// This is the content to copy to `destination`. If destination is a file,
// content will be written to that file, in case of a directory a file named
// `pkr-file-content` is created. It's recommended to use a file as the
// destination. A template_file might be referenced in here, or any
// interpolation syntax. This attribute cannot be specified with source or
// sources.
Content string `mapstructure:"content" required:"true"`
// The path to a local file or directory to upload to the
// machine. The path can be absolute or relative. If it is relative, it is
// relative to the working directory when Packer is executed. If this is a
@ -102,9 +110,14 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
}
}
if len(p.config.Sources) < 1 {
if len(p.config.Sources) < 1 && p.config.Content == "" {
errs = packersdk.MultiErrorAppend(errs,
errors.New("Source must be specified."))
errors.New("source, sources or content must be specified."))
}
if len(p.config.Sources) > 0 && p.config.Content != "" {
errs = packersdk.MultiErrorAppend(errs,
errors.New("source(s) conflicts with content."))
}
if p.config.Destination == "" {
@ -125,6 +138,19 @@ func (p *Provisioner) Provision(ctx context.Context, ui packersdk.Ui, comm packe
}
p.config.ctx.Data = generatedData
if p.config.Content != "" {
file, err := tmp.File("pkr-file-content")
if err != nil {
return err
}
defer file.Close()
if _, err := file.WriteString(p.config.Content); err != nil {
return err
}
p.config.Content = ""
p.config.Sources = append(p.config.Sources, file.Name())
}
if p.config.Direction == "download" {
return p.ProvisionDownload(ui, comm)
} else {

@ -18,6 +18,7 @@ type FlatConfig struct {
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
Content *string `mapstructure:"content" required:"true" cty:"content" hcl:"content"`
Source *string `mapstructure:"source" required:"true" cty:"source" hcl:"source"`
Sources []string `mapstructure:"sources" required:"false" cty:"sources" hcl:"sources"`
Destination *string `mapstructure:"destination" required:"true" cty:"destination" hcl:"destination"`
@ -45,6 +46,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"content": &hcldec.AttrSpec{Name: "content", Type: cty.String, Required: false},
"source": &hcldec.AttrSpec{Name: "source", Type: cty.String, Required: false},
"sources": &hcldec.AttrSpec{Name: "sources", Type: cty.List(cty.String), Required: false},
"destination": &hcldec.AttrSpec{Name: "destination", Type: cty.String, Required: false},

@ -151,6 +151,45 @@ func TestProvisionerProvision_SendsFile(t *testing.T) {
}
}
func TestProvisionerProvision_SendsContent(t *testing.T) {
var p Provisioner
dst := "something.txt"
content := "hello"
config := map[string]interface{}{
"content": content,
"destination": dst,
}
if err := p.Prepare(config); err != nil {
t.Fatalf("err: %s", err)
}
b := bytes.NewBuffer(nil)
ui := &packersdk.BasicUi{
Writer: b,
PB: &packersdk.NoopProgressTracker{},
}
comm := &packersdk.MockCommunicator{}
err := p.Provision(context.Background(), ui, comm, make(map[string]interface{}))
if err != nil {
t.Fatalf("should successfully provision: %s", err)
}
if !strings.Contains(b.String(), "something") {
t.Fatalf("should print destination filename")
}
if comm.UploadPath != dst {
t.Fatalf("should upload to configured destination")
}
if comm.UploadData != content {
t.Fatalf("should upload with source file's data")
}
}
func TestProvisionerProvision_SendsFileMultipleFiles(t *testing.T) {
var p Provisioner
tf1, err := ioutil.TempFile("", "packer")

@ -1,5 +1,12 @@
<!-- Code generated from the comments of the Config struct in provisioner/file/provisioner.go; DO NOT EDIT MANUALLY -->
- `content` (string) - This is the content to copy to `destination`. If destination is a file,
content will be written to that file, in case of a directory a file named
`pkr-file-content` is created. It's recommended to use a file as the
destination. A template_file might be referenced in here, or any
interpolation syntax. This attribute cannot be specified with source or
sources.
- `source` (string) - The path to a local file or directory to upload to the
machine. The path can be absolute or relative. If it is relative, it is
relative to the working directory when Packer is executed. If this is a

Loading…
Cancel
Save