github.com/mitchellh/packer@v1.3.2/builder/vmware/vmx/step_clone_vmx.go (about)

     1  package vmx
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  	"path/filepath"
     8  	"regexp"
     9  
    10  	vmwcommon "github.com/hashicorp/packer/builder/vmware/common"
    11  	"github.com/hashicorp/packer/helper/multistep"
    12  	"github.com/hashicorp/packer/packer"
    13  )
    14  
    15  // StepCloneVMX takes a VMX file and clones the VM into the output directory.
    16  type StepCloneVMX struct {
    17  	OutputDir string
    18  	Path      string
    19  	VMName    string
    20  	Linked    bool
    21  }
    22  
    23  func (s *StepCloneVMX) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
    24  	driver := state.Get("driver").(vmwcommon.Driver)
    25  	ui := state.Get("ui").(packer.Ui)
    26  
    27  	// Set the path we want for the new .vmx file and clone
    28  	vmxPath := filepath.Join(s.OutputDir, s.VMName+".vmx")
    29  	ui.Say("Cloning source VM...")
    30  	log.Printf("Cloning from: %s", s.Path)
    31  	log.Printf("Cloning to: %s", vmxPath)
    32  	if err := driver.Clone(vmxPath, s.Path, s.Linked); err != nil {
    33  		state.Put("error", err)
    34  		return multistep.ActionHalt
    35  	}
    36  
    37  	// Read in the machine configuration from the cloned VMX file
    38  	//
    39  	// * The main driver needs the path to the vmx (set above) and the
    40  	// network type so that it can work out things like IP's and MAC
    41  	// addresses
    42  	// * The disk compaction step needs the paths to all attached disks
    43  	vmxData, err := vmwcommon.ReadVMX(vmxPath)
    44  	if err != nil {
    45  		state.Put("error", err)
    46  		return multistep.ActionHalt
    47  	}
    48  
    49  	var diskFilenames []string
    50  	// The VMX file stores the path to a configured disk, and information
    51  	// about that disks attachment to a virtual adapter/controller, as a
    52  	// key/value pair.
    53  	// For a virtual disk attached to bus ID 3 of the virtual machines
    54  	// first SCSI adapter the key/value pair would look something like:
    55  	// scsi0:3.fileName = "relative/path/to/scsiDisk.vmdk"
    56  	// The supported adapter types and configuration maximums for each type
    57  	// vary according to the VMware platform type and version, and the
    58  	// Virtual Machine Hardware version used. See the 'Virtual Machine
    59  	// Maximums' section within VMware's 'Configuration Maximums'
    60  	// documentation for each platform:
    61  	// https://kb.vmware.com/s/article/1003497
    62  	// Information about the supported Virtual Machine Hardware versions:
    63  	// https://kb.vmware.com/s/article/1003746
    64  	// The following regexp is used to match all possible disk attachment
    65  	// points that may be found in the VMX file across all VMware
    66  	// platforms/versions and Virtual Machine Hardware versions
    67  	diskPathKeyRe := regexp.MustCompile(`(?i)^(scsi|sata|ide|nvme)[[:digit:]]:[[:digit:]]{1,2}\.fileName`)
    68  	for k, v := range vmxData {
    69  		match := diskPathKeyRe.FindString(k)
    70  		if match != "" && filepath.Ext(v) == ".vmdk" {
    71  			diskFilenames = append(diskFilenames, v)
    72  		}
    73  	}
    74  
    75  	// Write out the relative, host filesystem paths to the disks
    76  	var diskFullPaths []string
    77  	for _, diskFilename := range diskFilenames {
    78  		log.Printf("Found attached disk with filename: %s", diskFilename)
    79  		diskFullPaths = append(diskFullPaths, filepath.Join(s.OutputDir, diskFilename))
    80  	}
    81  
    82  	if len(diskFullPaths) == 0 {
    83  		state.Put("error", fmt.Errorf("Could not enumerate disk info from the vmx file"))
    84  		return multistep.ActionHalt
    85  	}
    86  
    87  	// Determine the network type by reading out of the .vmx
    88  	var networkType string
    89  	if _, ok := vmxData["ethernet0.connectiontype"]; ok {
    90  		networkType = vmxData["ethernet0.connectiontype"]
    91  		log.Printf("Discovered the network type: %s", networkType)
    92  	}
    93  	if networkType == "" {
    94  		networkType = "nat"
    95  		log.Printf("Defaulting to network type: %s", networkType)
    96  	}
    97  
    98  	// Stash all required information in our state bag
    99  	state.Put("vmx_path", vmxPath)
   100  	state.Put("disk_full_paths", diskFullPaths)
   101  	state.Put("vmnetwork", networkType)
   102  
   103  	return multistep.ActionContinue
   104  }
   105  
   106  func (s *StepCloneVMX) Cleanup(state multistep.StateBag) {
   107  }