github.phpd.cn/hashicorp/packer@v1.3.2/builder/amazon/chroot/step_mount_extra.go (about)

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