diff --git a/builder/amazon/chroot/builder.go b/builder/amazon/chroot/builder.go index ceb4a5c76..d52a14987 100644 --- a/builder/amazon/chroot/builder.go +++ b/builder/amazon/chroot/builder.go @@ -24,13 +24,13 @@ type Config struct { common.PackerConfig `mapstructure:",squash"` awscommon.AccessConfig `mapstructure:",squash"` - AttachedDevicePath string `mapstructure:"attached_device_path"` - ChrootMounts []string `mapstructure:"chroot_mounts"` - DevicePath string `mapstructure:"device_path"` - MountCommand string `mapstructure:"mount_command"` - MountPath string `mapstructure:"mount_path"` - SourceAmi string `mapstructure:"source_ami"` - UnmountCommand string `mapstructure:"unmount_command"` + AttachedDevicePath string `mapstructure:"attached_device_path"` + ChrootMounts [][]string `mapstructure:"chroot_mounts"` + DevicePath string `mapstructure:"device_path"` + MountCommand string `mapstructure:"mount_command"` + MountPath string `mapstructure:"mount_path"` + SourceAmi string `mapstructure:"source_ami"` + UnmountCommand string `mapstructure:"unmount_command"` } type Builder struct { @@ -46,16 +46,16 @@ func (b *Builder) Prepare(raws ...interface{}) error { // Defaults if b.config.ChrootMounts == nil { - b.config.ChrootMounts = make([]string, 0) + b.config.ChrootMounts = make([][]string, 0) } if len(b.config.ChrootMounts) == 0 { - b.config.ChrootMounts = []string{ - "{{.MountCommand}} -t proc proc {{.MountPath}}/proc", - "{{.MountCommand}} -t sysfs sysfs {{.MountPath}}/sys", - "{{.MountCommand}} -t bind /dev {{.MountPath}}/dev", - "{{.MountCommand}} -t devpts devpts {{.MountPath}}/dev/pts", - "{{.MountCommand}} -t binfmt_misc binfmt_misc {{.MountPath}}/proc/sys/fs/binfmt_misc", + b.config.ChrootMounts = [][]string{ + []string{"proc", "proc", "/proc"}, + []string{"sysfs", "sysfs", "/sys"}, + []string{"bind", "/dev", "/dev"}, + []string{"devpts", "devpts", "/dev/pts"}, + []string{"binfmt_misc", "binfmt_misc", "/proc/sys/fs/binfmt_misc"}, } } @@ -126,6 +126,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe &StepCreateVolume{}, &StepAttachVolume{}, &StepMountDevice{}, + &StepMountExtra{}, } // Run! diff --git a/builder/amazon/chroot/step_mount_device.go b/builder/amazon/chroot/step_mount_device.go index 2dcb94945..0c68986da 100644 --- a/builder/amazon/chroot/step_mount_device.go +++ b/builder/amazon/chroot/step_mount_device.go @@ -32,7 +32,7 @@ func (s *StepMountDevice) Run(state map[string]interface{}) multistep.StepAction mountPathRaw := new(bytes.Buffer) t := template.Must(template.New("mountPath").Parse(config.MountPath)) t.Execute(mountPathRaw, &mountPathData{ - Device: filepath.Basename(device), + Device: filepath.Base(device), }) mountPath := mountPathRaw.String() @@ -60,6 +60,7 @@ func (s *StepMountDevice) Run(state map[string]interface{}) multistep.StepAction // Set the mount path so we remember to unmount it later s.mountPath = mountPath + state["mount_path"] = s.mountPath return multistep.ActionContinue } diff --git a/builder/amazon/chroot/step_mount_extra.go b/builder/amazon/chroot/step_mount_extra.go new file mode 100644 index 000000000..8ce4d3794 --- /dev/null +++ b/builder/amazon/chroot/step_mount_extra.go @@ -0,0 +1,79 @@ +package chroot + +import ( + "bytes" + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "os" + "os/exec" +) + +// StepMountExtra mounts the attached device. +// +// Produces: +// mount_path string - The location where the volume was mounted. +type StepMountExtra struct { + mounts []string +} + +func (s *StepMountExtra) Run(state map[string]interface{}) multistep.StepAction { + config := state["config"].(*Config) + mountPath := state["mount_path"].(string) + ui := state["ui"].(packer.Ui) + + 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["error"] = err + ui.Error(err.Error()) + return multistep.ActionHalt + } + + ui.Message(fmt.Sprintf("Mounting: %s", mountInfo[2])) + stderr := new(bytes.Buffer) + mountCommand := fmt.Sprintf( + "%s -t %s %s %s", + config.MountCommand, + mountInfo[0], + mountInfo[1], + innerPath) + cmd := exec.Command("/bin/sh", "-c", mountCommand) + cmd.Stderr = stderr + if err := cmd.Run(); err != nil { + err := fmt.Errorf( + "Error mounting: %s\nStderr: %s", err, stderr.String()) + state["error"] = err + ui.Error(err.Error()) + return multistep.ActionHalt + } + + s.mounts = append(s.mounts, innerPath) + } + + return multistep.ActionContinue +} + +func (s *StepMountExtra) Cleanup(state map[string]interface{}) { + if s.mounts == nil { + return + } + + config := state["config"].(*Config) + ui := state["ui"].(packer.Ui) + + for _, path := range s.mounts { + unmountCommand := fmt.Sprintf("%s %s", config.UnmountCommand, path) + cmd := exec.Command("bin/sh", "-c", unmountCommand) + if err := cmd.Run(); err != nil { + ui.Error(fmt.Sprintf( + "Error unmounting root device: %s", err)) + return + } + } +}