diff --git a/builder/osc/chroot/builder.go b/builder/osc/chroot/builder.go index b5bcb907e..1b5019653 100644 --- a/builder/osc/chroot/builder.go +++ b/builder/osc/chroot/builder.go @@ -249,6 +249,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe }, &StepLinkVolume{}, &StepEarlyUnflock{}, + &StepPreMountCommands{ + Commands: b.config.PreMountCommands, + }, ) // Run! diff --git a/builder/osc/chroot/run_local_commands.go b/builder/osc/chroot/run_local_commands.go new file mode 100644 index 000000000..fc1c01e2b --- /dev/null +++ b/builder/osc/chroot/run_local_commands.go @@ -0,0 +1,39 @@ +package chroot + +import ( + "fmt" + + sl "github.com/hashicorp/packer/common/shell-local" + "github.com/hashicorp/packer/packer" + "github.com/hashicorp/packer/template/interpolate" +) + +func RunLocalCommands(commands []string, wrappedCommand CommandWrapper, ctx interpolate.Context, ui packer.Ui) error { + for _, rawCmd := range commands { + intCmd, err := interpolate.Render(rawCmd, &ctx) + if err != nil { + return fmt.Errorf("Error interpolating: %s", err) + } + + command, err := wrappedCommand(intCmd) + if err != nil { + return fmt.Errorf("Error wrapping command: %s", err) + } + + ui.Say(fmt.Sprintf("Executing command: %s", command)) + comm := &sl.Communicator{ + ExecuteCommand: []string{"sh", "-c", command}, + } + cmd := &packer.RemoteCmd{Command: command} + if err := cmd.StartWithUi(comm, ui); err != nil { + return fmt.Errorf("Error executing command: %s", err) + } + if cmd.ExitStatus != 0 { + return fmt.Errorf( + "Received non-zero exit code %d from command: %s", + cmd.ExitStatus, + command) + } + } + return nil +} diff --git a/builder/osc/chroot/step_pre_mount_commands.go b/builder/osc/chroot/step_pre_mount_commands.go new file mode 100644 index 000000000..ce3c26e02 --- /dev/null +++ b/builder/osc/chroot/step_pre_mount_commands.go @@ -0,0 +1,41 @@ +package chroot + +import ( + "context" + + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" +) + +type preMountCommandsData struct { + Device string +} + +// StepPreMountCommands sets up the a new block device when building from scratch +type StepPreMountCommands struct { + Commands []string +} + +func (s *StepPreMountCommands) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { + config := state.Get("config").(*Config) + device := state.Get("device").(string) + ui := state.Get("ui").(packer.Ui) + wrappedCommand := state.Get("wrappedCommand").(CommandWrapper) + + if len(s.Commands) == 0 { + return multistep.ActionContinue + } + + ctx := config.ctx + ctx.Data = &preMountCommandsData{Device: device} + + ui.Say("Running device setup commands...") + if err := RunLocalCommands(s.Commands, wrappedCommand, ctx, ui); err != nil { + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + return multistep.ActionContinue +} + +func (s *StepPreMountCommands) Cleanup(state multistep.StateBag) {}