github.com/rothwerx/packer@v0.9.0/builder/amazon/chroot/step_mount_extra.go (about)

     1  package chroot
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"github.com/mitchellh/multistep"
     7  	"github.com/mitchellh/packer/packer"
     8  	"os"
     9  	"os/exec"
    10  	"syscall"
    11  )
    12  
    13  // StepMountExtra mounts the attached device.
    14  //
    15  // Produces:
    16  //   mount_extra_cleanup CleanupFunc - To perform early cleanup
    17  type StepMountExtra struct {
    18  	mounts []string
    19  }
    20  
    21  func (s *StepMountExtra) Run(state multistep.StateBag) multistep.StepAction {
    22  	config := state.Get("config").(*Config)
    23  	mountPath := state.Get("mount_path").(string)
    24  	ui := state.Get("ui").(packer.Ui)
    25  	wrappedCommand := state.Get("wrappedCommand").(CommandWrapper)
    26  
    27  	s.mounts = make([]string, 0, len(config.ChrootMounts))
    28  
    29  	ui.Say("Mounting additional paths within the chroot...")
    30  	for _, mountInfo := range config.ChrootMounts {
    31  		innerPath := mountPath + mountInfo[2]
    32  
    33  		if err := os.MkdirAll(innerPath, 0755); err != nil {
    34  			err := fmt.Errorf("Error creating mount directory: %s", err)
    35  			state.Put("error", err)
    36  			ui.Error(err.Error())
    37  			return multistep.ActionHalt
    38  		}
    39  
    40  		flags := "-t " + mountInfo[0]
    41  		if mountInfo[0] == "bind" {
    42  			flags = "--bind"
    43  		}
    44  
    45  		ui.Message(fmt.Sprintf("Mounting: %s", mountInfo[2]))
    46  		stderr := new(bytes.Buffer)
    47  		mountCommand, err := wrappedCommand(fmt.Sprintf(
    48  			"mount %s %s %s",
    49  			flags,
    50  			mountInfo[1],
    51  			innerPath))
    52  		if err != nil {
    53  			err := fmt.Errorf("Error creating mount command: %s", err)
    54  			state.Put("error", err)
    55  			ui.Error(err.Error())
    56  			return multistep.ActionHalt
    57  		}
    58  
    59  		cmd := ShellCommand(mountCommand)
    60  		cmd.Stderr = stderr
    61  		if err := cmd.Run(); err != nil {
    62  			err := fmt.Errorf(
    63  				"Error mounting: %s\nStderr: %s", err, stderr.String())
    64  			state.Put("error", err)
    65  			ui.Error(err.Error())
    66  			return multistep.ActionHalt
    67  		}
    68  
    69  		s.mounts = append(s.mounts, innerPath)
    70  	}
    71  
    72  	state.Put("mount_extra_cleanup", s)
    73  	return multistep.ActionContinue
    74  }
    75  
    76  func (s *StepMountExtra) Cleanup(state multistep.StateBag) {
    77  	ui := state.Get("ui").(packer.Ui)
    78  
    79  	if err := s.CleanupFunc(state); err != nil {
    80  		ui.Error(err.Error())
    81  		return
    82  	}
    83  }
    84  
    85  func (s *StepMountExtra) CleanupFunc(state multistep.StateBag) error {
    86  	if s.mounts == nil {
    87  		return nil
    88  	}
    89  
    90  	wrappedCommand := state.Get("wrappedCommand").(CommandWrapper)
    91  	for len(s.mounts) > 0 {
    92  		var path string
    93  		lastIndex := len(s.mounts) - 1
    94  		path, s.mounts = s.mounts[lastIndex], s.mounts[:lastIndex]
    95  
    96  		grepCommand, err := wrappedCommand(fmt.Sprintf("grep %s /proc/mounts", path))
    97  		if err != nil {
    98  			return fmt.Errorf("Error creating grep command: %s", err)
    99  		}
   100  
   101  		// Before attempting to unmount,
   102  		// check to see if path is already unmounted
   103  		stderr := new(bytes.Buffer)
   104  		cmd := ShellCommand(grepCommand)
   105  		cmd.Stderr = stderr
   106  		if err := cmd.Run(); err != nil {
   107  			if exitError, ok := err.(*exec.ExitError); ok {
   108  				if status, ok := exitError.Sys().(syscall.WaitStatus); ok {
   109  					exitStatus := status.ExitStatus()
   110  					if exitStatus == 1 {
   111  						// path has already been unmounted
   112  						// just skip this path
   113  						continue
   114  					}
   115  				}
   116  			}
   117  		}
   118  
   119  		unmountCommand, err := wrappedCommand(fmt.Sprintf("umount %s", path))
   120  		if err != nil {
   121  			return fmt.Errorf("Error creating unmount command: %s", err)
   122  		}
   123  
   124  		stderr = new(bytes.Buffer)
   125  		cmd = ShellCommand(unmountCommand)
   126  		cmd.Stderr = stderr
   127  		if err := cmd.Run(); err != nil {
   128  			return fmt.Errorf(
   129  				"Error unmounting device: %s\nStderr: %s", err, stderr.String())
   130  		}
   131  	}
   132  
   133  	s.mounts = nil
   134  	return nil
   135  }