/cc @mwhooker - I changed the interface up a bit to return an error, since things should return errors in Go (the ui.Error bit was kind of ghetto because it had no way to bubble that error up except through the UI). Using this, I made it so that the communicator uses both a CommandWrapper and ShellCommand with chroot so that the chroot commannd is also wrapped (it wasn't before). I think the functionality of all this is the same but I'd love if you could look it over and make sure.
110 lines
2.7 KiB
Go
110 lines
2.7 KiB
Go
package chroot
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"github.com/mitchellh/multistep"
|
|
"github.com/mitchellh/packer/packer"
|
|
"os"
|
|
)
|
|
|
|
// StepMountExtra mounts the attached device.
|
|
//
|
|
// Produces:
|
|
// mount_extra_cleanup CleanupFunc - To perform early cleanup
|
|
type StepMountExtra struct {
|
|
mounts []string
|
|
}
|
|
|
|
func (s *StepMountExtra) Run(state multistep.StateBag) multistep.StepAction {
|
|
config := state.Get("config").(*Config)
|
|
mountPath := state.Get("mount_path").(string)
|
|
ui := state.Get("ui").(packer.Ui)
|
|
wrappedCommand := state.Get("wrappedCommand").(CommandWrapper)
|
|
|
|
s.mounts = make([]string, 0, len(config.ChrootMounts))
|
|
|
|
ui.Say("Mounting additional paths within the chroot...")
|
|
for _, mountInfo := range config.ChrootMounts {
|
|
innerPath := mountPath + mountInfo[2]
|
|
|
|
if err := os.MkdirAll(innerPath, 0755); err != nil {
|
|
err := fmt.Errorf("Error creating mount directory: %s", err)
|
|
state.Put("error", err)
|
|
ui.Error(err.Error())
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
flags := "-t " + mountInfo[0]
|
|
if mountInfo[0] == "bind" {
|
|
flags = "--bind"
|
|
}
|
|
|
|
ui.Message(fmt.Sprintf("Mounting: %s", mountInfo[2]))
|
|
stderr := new(bytes.Buffer)
|
|
mountCommand, err := wrappedCommand(fmt.Sprintf(
|
|
"mount %s %s %s",
|
|
flags,
|
|
mountInfo[1],
|
|
innerPath))
|
|
if err != nil {
|
|
err := fmt.Errorf("Error creating mount command: %s", err)
|
|
state.Put("error", err)
|
|
ui.Error(err.Error())
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
cmd := ShellCommand(mountCommand)
|
|
cmd.Stderr = stderr
|
|
if err := cmd.Run(); err != nil {
|
|
err := fmt.Errorf(
|
|
"Error mounting: %s\nStderr: %s", err, stderr.String())
|
|
state.Put("error", err)
|
|
ui.Error(err.Error())
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
s.mounts = append(s.mounts, innerPath)
|
|
}
|
|
|
|
state.Put("mount_extra_cleanup", s)
|
|
return multistep.ActionContinue
|
|
}
|
|
|
|
func (s *StepMountExtra) Cleanup(state multistep.StateBag) {
|
|
ui := state.Get("ui").(packer.Ui)
|
|
|
|
if err := s.CleanupFunc(state); err != nil {
|
|
ui.Error(err.Error())
|
|
return
|
|
}
|
|
}
|
|
|
|
func (s *StepMountExtra) CleanupFunc(state multistep.StateBag) error {
|
|
if s.mounts == nil {
|
|
return nil
|
|
}
|
|
|
|
wrappedCommand := state.Get("wrappedCommand").(CommandWrapper)
|
|
for len(s.mounts) > 0 {
|
|
var path string
|
|
lastIndex := len(s.mounts) - 1
|
|
path, s.mounts = s.mounts[lastIndex], s.mounts[:lastIndex]
|
|
unmountCommand, err := wrappedCommand(fmt.Sprintf("umount %s", path))
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating unmount command: %s", err)
|
|
}
|
|
|
|
stderr := new(bytes.Buffer)
|
|
cmd := ShellCommand(unmountCommand)
|
|
cmd.Stderr = stderr
|
|
if err := cmd.Run(); err != nil {
|
|
return fmt.Errorf(
|
|
"Error unmounting device: %s\nStderr: %s", err, stderr.String())
|
|
}
|
|
}
|
|
|
|
s.mounts = nil
|
|
return nil
|
|
}
|