packer-cn/builder/amazon/chroot/step_mount_extra.go
Mitchell Hashimoto b554a0dd86 builder/amazon/chroot: CommandWrapper
/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.
2013-09-30 09:33:57 -07:00

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
}