Interpolate vagrantfile_template on Vagrant post-processor (#9923)

This commit is contained in:
Sylvia Moss 2020-09-16 10:08:44 +02:00 committed by GitHub
parent aeb70e6726
commit bdd736b800
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 147 additions and 13 deletions

View File

@ -5,6 +5,7 @@ import (
"log"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/builder"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep"
@ -29,7 +30,9 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
return nil, warnings, errs
}
return nil, warnings, nil
return []string{
"ImageSha256",
}, warnings, nil
}
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
@ -44,6 +47,16 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
}
log.Printf("[DEBUG] Docker version: %s", version.String())
// Setup the state bag and initial state for the steps
state := new(multistep.BasicStateBag)
state.Put("config", &b.config)
state.Put("hook", hook)
state.Put("ui", ui)
generatedData := &builder.GeneratedData{State: state}
// Setup the driver that will talk to Docker
state.Put("driver", driver)
steps := []multistep.Step{
&StepTempDir{},
&StepPull{},
@ -67,7 +80,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
log.Print("[DEBUG] Container will be discarded")
} else if b.config.Commit {
log.Print("[DEBUG] Container will be committed")
steps = append(steps, new(StepCommit))
steps = append(steps,
new(StepCommit),
&StepSetGeneratedData{ // Adds ImageSha256 variable available after StepCommit
GeneratedData: generatedData,
})
} else if b.config.ExportPath != "" {
log.Printf("[DEBUG] Container will be exported to %s", b.config.ExportPath)
steps = append(steps, new(StepExport))
@ -75,15 +92,6 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
return nil, errArtifactNotUsed
}
// Setup the state bag and initial state for the steps
state := new(multistep.BasicStateBag)
state.Put("config", &b.config)
state.Put("hook", hook)
state.Put("ui", ui)
// Setup the driver that will talk to Docker
state.Put("driver", driver)
// Run!
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
b.runner.Run(ctx, state)

View File

@ -26,6 +26,9 @@ type Driver interface {
// for external access.
IPAddress(id string) (string, error)
// Sha256 returns the sha256 id of the image
Sha256(id string) (string, error)
// Login. This will lock the driver from performing another Login
// until Logout is called. Therefore, any users MUST call Logout.
Login(repo, username, password string) error

View File

@ -159,6 +159,23 @@ func (d *DockerDriver) IPAddress(id string) (string, error) {
return strings.TrimSpace(stdout.String()), nil
}
func (d *DockerDriver) Sha256(id string) (string, error) {
var stderr, stdout bytes.Buffer
cmd := exec.Command(
"docker",
"inspect",
"--format",
"{{ .Id }}",
id)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return "", fmt.Errorf("Error: %s\n\nStderr: %s", err, stderr.String())
}
return strings.TrimSpace(stdout.String()), nil
}
func (d *DockerDriver) Login(repo, user, pass string) error {
d.l.Lock()

View File

@ -28,6 +28,11 @@ type MockDriver struct {
IPAddressResult string
IPAddressErr error
Sha256Called bool
Sha256Id string
Sha256Result string
Sha256Err error
KillCalled bool
KillID string
KillError error
@ -118,6 +123,12 @@ func (d *MockDriver) IPAddress(id string) (string, error) {
return d.IPAddressResult, d.IPAddressErr
}
func (d *MockDriver) Sha256(id string) (string, error) {
d.Sha256Called = true
d.Sha256Id = id
return d.Sha256Result, d.Sha256Err
}
func (d *MockDriver) Login(r, u, p string) error {
d.LoginCalled = true
d.LoginRepo = r

View File

@ -0,0 +1,30 @@
package docker
import (
"context"
"github.com/hashicorp/packer/builder"
"github.com/hashicorp/packer/helper/multistep"
)
type StepSetGeneratedData struct {
GeneratedData *builder.GeneratedData
}
func (s *StepSetGeneratedData) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(Driver)
sha256 := "ERR_IMAGE_SHA256_NOT_FOUND"
if imageId, ok := state.GetOk("image_id"); ok {
s256, err := driver.Sha256(imageId.(string))
if err == nil {
sha256 = s256
}
}
s.GeneratedData.Put("ImageSha256", sha256)
return multistep.ActionContinue
}
func (s *StepSetGeneratedData) Cleanup(_ multistep.StateBag) {
// No cleanup...
}

View File

@ -0,0 +1,51 @@
package docker
import (
"context"
"testing"
"github.com/hashicorp/packer/builder"
"github.com/hashicorp/packer/helper/multistep"
)
func TestStepSetGeneratedData_Run(t *testing.T) {
state := testState(t)
step := new(StepSetGeneratedData)
step.GeneratedData = &builder.GeneratedData{State: state}
driver := state.Get("driver").(*MockDriver)
driver.Sha256Result = "80B3BB1B1696E73A9B19DEEF92F664F8979F948DF348088B61F9A3477655AF64"
state.Put("image_id", "12345")
if action := step.Run(context.TODO(), state); action != multistep.ActionContinue {
t.Fatalf("Should not halt")
}
if !driver.Sha256Called {
t.Fatalf("driver.SHA256 should be called")
}
if driver.Sha256Id != "12345" {
t.Fatalf("driver.SHA256 got wrong image it: %s", driver.Sha256Id)
}
genData := state.Get("generated_data").(map[string]interface{})
imgSha256 := genData["ImageSha256"].(string)
if imgSha256 != driver.Sha256Result {
t.Fatalf("Expected ImageSha256 to be %s but was %s", driver.Sha256Result, imgSha256)
}
// Image ID not implement
state = testState(t)
step.GeneratedData = &builder.GeneratedData{State: state}
driver = state.Get("driver").(*MockDriver)
notImplementedMsg := "ERR_IMAGE_SHA256_NOT_FOUND"
if action := step.Run(context.TODO(), state); action != multistep.ActionContinue {
t.Fatalf("Should not halt")
}
if driver.Sha256Called {
t.Fatalf("driver.SHA256 should not be called")
}
genData = state.Get("generated_data").(map[string]interface{})
imgSha256 = genData["ImageSha256"].(string)
if imgSha256 != notImplementedMsg {
t.Fatalf("Expected ImageSha256 to be %s but was %s", notImplementedMsg, imgSha256)
}
}

View File

@ -175,7 +175,10 @@ func (p *PostProcessor) PostProcessProvider(name string, provider Provider, ui p
return nil, false, err
}
customVagrantfile = string(customBytes)
customVagrantfile, err = interpolate.Render(string(customBytes), &config.ctx)
if err != nil {
return nil, false, err
}
}
f, err := os.Create(filepath.Join(dir, "Vagrantfile"))

View File

@ -215,6 +215,16 @@ You must specify (only) one of `commit`, `discard`, or `export_path`.
@include 'builder/docker/Config-not-required.mdx'
## Build Shared Information Variables
This build shares generated data with provisioners and post-processors via [template engines](/docs/templates/engine)
for JSON and [contextual variables](/docs/from-1.5/contextual-variables) for HCL2.
The generated variable available for this builder is:
- `ImageSha256` - When committing a container to an image, this will give the image SHA256. Because the image is not available at the provision step,
this variable is only available for post-processors.
## Using the Artifact: Export
Once the tar artifact has been generated, you will likely want to import, tag,

View File

@ -102,7 +102,8 @@ more details about certain options in following sections.
`lxc`, `scaleway`, `hyperv`, `parallels`, `aws`, or `google`.
- `vagrantfile_template` (string) - Path to a template to use for the
Vagrantfile that is packaged with the box.
Vagrantfile that is packaged with the box. This option supports the usage of the [template engine](/docs/templates/engine)
for JSON and the [contextual variables](/docs/from-1.5/contextual-variables) for HCL2.
- `vagrantfile_template_generated` (boolean) - By default, Packer will
exit with an error if the file specified using the