Interpolate vagrantfile_template on Vagrant post-processor (#9923)
This commit is contained in:
parent
aeb70e6726
commit
bdd736b800
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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
|
||||
|
30
builder/docker/step_set_generated_data.go
Normal file
30
builder/docker/step_set_generated_data.go
Normal 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...
|
||||
}
|
51
builder/docker/step_set_generated_data_test.go
Normal file
51
builder/docker/step_set_generated_data_test.go
Normal 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)
|
||||
}
|
||||
}
|
@ -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"))
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user