github.com/vijayrajah/packer@v1.3.2/post-processor/vsphere-template/step_mark_as_template.go (about) 1 package vsphere_template 2 3 import ( 4 "context" 5 "fmt" 6 "path" 7 "regexp" 8 "strings" 9 10 "github.com/hashicorp/packer/helper/multistep" 11 "github.com/hashicorp/packer/packer" 12 "github.com/hashicorp/packer/post-processor/vsphere" 13 "github.com/vmware/govmomi" 14 "github.com/vmware/govmomi/object" 15 "github.com/vmware/govmomi/vim25/types" 16 ) 17 18 type stepMarkAsTemplate struct { 19 VMName string 20 RemoteFolder string 21 } 22 23 func NewStepMarkAsTemplate(artifact packer.Artifact) *stepMarkAsTemplate { 24 remoteFolder := "Discovered virtual machine" 25 vmname := artifact.Id() 26 27 if artifact.BuilderId() == vsphere.BuilderId { 28 id := strings.Split(artifact.Id(), "::") 29 remoteFolder = id[1] 30 vmname = id[2] 31 } 32 33 return &stepMarkAsTemplate{ 34 VMName: vmname, 35 RemoteFolder: remoteFolder, 36 } 37 } 38 39 func (s *stepMarkAsTemplate) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { 40 ui := state.Get("ui").(packer.Ui) 41 cli := state.Get("client").(*govmomi.Client) 42 folder := state.Get("folder").(*object.Folder) 43 dcPath := state.Get("dcPath").(string) 44 45 ui.Message("Marking as a template...") 46 47 vm, err := findRuntimeVM(cli, dcPath, s.VMName, s.RemoteFolder) 48 if err != nil { 49 state.Put("error", err) 50 ui.Error(err.Error()) 51 return multistep.ActionHalt 52 } 53 54 dsPath, err := datastorePath(vm) 55 if err != nil { 56 state.Put("error", err) 57 ui.Error(err.Error()) 58 return multistep.ActionHalt 59 } 60 61 host, err := vm.HostSystem(context.Background()) 62 if err != nil { 63 state.Put("error", err) 64 ui.Error(err.Error()) 65 return multistep.ActionHalt 66 } 67 68 if err := vm.Unregister(context.Background()); err != nil { 69 state.Put("error", err) 70 ui.Error(err.Error()) 71 return multistep.ActionHalt 72 } 73 74 if err := unregisterPreviousVM(cli, folder, s.VMName); err != nil { 75 state.Put("error", err) 76 ui.Error(err.Error()) 77 return multistep.ActionHalt 78 } 79 80 task, err := folder.RegisterVM(context.Background(), dsPath.String(), s.VMName, true, nil, host) 81 if err != nil { 82 state.Put("error", err) 83 ui.Error(err.Error()) 84 return multistep.ActionHalt 85 } 86 87 if err = task.Wait(context.Background()); err != nil { 88 state.Put("error", err) 89 ui.Error(err.Error()) 90 return multistep.ActionHalt 91 } 92 93 return multistep.ActionContinue 94 } 95 96 func datastorePath(vm *object.VirtualMachine) (*object.DatastorePath, error) { 97 devices, err := vm.Device(context.Background()) 98 if err != nil { 99 return nil, err 100 } 101 102 disk := "" 103 for _, device := range devices { 104 if d, ok := device.(*types.VirtualDisk); ok { 105 if b, ok := d.Backing.(types.BaseVirtualDeviceFileBackingInfo); ok { 106 disk = b.GetVirtualDeviceFileBackingInfo().FileName 107 } 108 break 109 } 110 } 111 112 if disk == "" { 113 return nil, fmt.Errorf("disk not found in '%v'", vm.Name()) 114 } 115 116 re := regexp.MustCompile("\\[(.*?)\\]") 117 118 datastore := re.FindStringSubmatch(disk)[1] 119 vmxPath := path.Join("/", path.Dir(strings.Split(disk, " ")[1]), vm.Name()+".vmx") 120 121 return &object.DatastorePath{ 122 Datastore: datastore, 123 Path: vmxPath, 124 }, nil 125 } 126 127 func findRuntimeVM(cli *govmomi.Client, dcPath, name, remoteFolder string) (*object.VirtualMachine, error) { 128 si := object.NewSearchIndex(cli.Client) 129 fullPath := path.Join(dcPath, "vm", remoteFolder, name) 130 131 ref, err := si.FindByInventoryPath(context.Background(), fullPath) 132 if err != nil { 133 return nil, err 134 } 135 136 if ref == nil { 137 return nil, fmt.Errorf("VM at path %s not found", fullPath) 138 } 139 140 vm := ref.(*object.VirtualMachine) 141 if vm.InventoryPath == "" { 142 vm.SetInventoryPath(fullPath) 143 } 144 145 return vm, nil 146 } 147 148 // If in the target folder a virtual machine or template already exists 149 // it will be removed to maintain consistency 150 func unregisterPreviousVM(cli *govmomi.Client, folder *object.Folder, name string) error { 151 si := object.NewSearchIndex(cli.Client) 152 fullPath := path.Join(folder.InventoryPath, name) 153 154 ref, err := si.FindByInventoryPath(context.Background(), fullPath) 155 if err != nil { 156 return err 157 } 158 159 if ref != nil { 160 if vm, ok := ref.(*object.VirtualMachine); ok { 161 return vm.Unregister(context.Background()) 162 } else { 163 return fmt.Errorf("an object name '%v' already exists", name) 164 } 165 166 } 167 168 return nil 169 } 170 171 func (s *stepMarkAsTemplate) Cleanup(multistep.StateBag) {}