128 lines
3.3 KiB
Go
128 lines
3.3 KiB
Go
package common
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/hashicorp/packer/helper/multistep"
|
|
"github.com/hashicorp/packer/packer"
|
|
)
|
|
|
|
// StepOutputDir sets up the output directory by creating it if it does
|
|
// not exist, deleting it if it does exist and we're forcing, and cleaning
|
|
// it up when we're done with it.
|
|
type StepOutputDir struct {
|
|
Force bool
|
|
|
|
OutputConfig *OutputConfig
|
|
VMName string
|
|
|
|
RemoteType string
|
|
|
|
success bool
|
|
}
|
|
|
|
func (s *StepOutputDir) SetOutputAndExportDirs(state multistep.StateBag) OutputDir {
|
|
driver := state.Get("driver")
|
|
|
|
// Hold on to your pants. The output configuration is a little more complex
|
|
// than you'd expect because of all the moving parts between local and
|
|
// remote output, and exports, and legacy behavior.
|
|
var dir OutputDir
|
|
switch d := driver.(type) {
|
|
case OutputDir:
|
|
// The driver fulfils the OutputDir interface so that it can create
|
|
// output files on the remote instance.
|
|
dir = d
|
|
default:
|
|
// The driver will be running the build and creating the output
|
|
// directory locally
|
|
dir = new(LocalOutputDir)
|
|
}
|
|
|
|
// If remote type is esx, we need to track both the output dir on the remote
|
|
// instance and the output dir locally. exportOutputPath is where we track
|
|
// the local output dir.
|
|
exportOutputPath := s.OutputConfig.OutputDir
|
|
|
|
if s.RemoteType != "" {
|
|
if s.OutputConfig.RemoteOutputDir != "" {
|
|
// User set the remote output dir.
|
|
s.OutputConfig.OutputDir = s.OutputConfig.RemoteOutputDir
|
|
} else {
|
|
// Default output dir to vm name. On remote esx instance, this will
|
|
// become something like /vmfs/volumes/mydatastore/vmname/vmname.vmx
|
|
s.OutputConfig.OutputDir = s.VMName
|
|
}
|
|
}
|
|
// Remember, this one's either the output from a local build, or the remote
|
|
// output from a remote build. Not the local export path for a remote build.
|
|
dir.SetOutputDir(s.OutputConfig.OutputDir)
|
|
|
|
// Set dir in the state for use in file cleanup and artifact
|
|
state.Put("dir", dir)
|
|
state.Put("export_output_path", exportOutputPath)
|
|
return dir
|
|
}
|
|
|
|
func (s *StepOutputDir) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
|
ui := state.Get("ui").(packer.Ui)
|
|
ui.Say("Configuring output and export directories...")
|
|
|
|
dir := s.SetOutputAndExportDirs(state)
|
|
exists, err := dir.DirExists()
|
|
if err != nil {
|
|
state.Put("error", err)
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
if exists {
|
|
if s.Force {
|
|
ui.Message("Deleting previous output directory...")
|
|
dir.RemoveAll()
|
|
} else {
|
|
state.Put("error", fmt.Errorf(
|
|
"Output directory '%s' already exists.", dir.String()))
|
|
return multistep.ActionHalt
|
|
}
|
|
}
|
|
|
|
if err := dir.MkdirAll(); err != nil {
|
|
state.Put("error", err)
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
s.success = true
|
|
return multistep.ActionContinue
|
|
}
|
|
|
|
func (s *StepOutputDir) Cleanup(state multistep.StateBag) {
|
|
if !s.success {
|
|
return
|
|
}
|
|
|
|
_, cancelled := state.GetOk(multistep.StateCancelled)
|
|
_, halted := state.GetOk(multistep.StateHalted)
|
|
|
|
if cancelled || halted {
|
|
dir := state.Get("dir").(OutputDir)
|
|
ui := state.Get("ui").(packer.Ui)
|
|
|
|
exists, _ := dir.DirExists()
|
|
if exists {
|
|
ui.Say("Deleting output directory...")
|
|
for i := 0; i < 5; i++ {
|
|
err := dir.RemoveAll()
|
|
if err == nil {
|
|
break
|
|
}
|
|
|
|
log.Printf("Error removing output dir: %s", err)
|
|
time.Sleep(2 * time.Second)
|
|
}
|
|
}
|
|
}
|
|
}
|