github.phpd.cn/hashicorp/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 }