diff --git a/builder/vsphere/common/step_import_to_content_library.go b/builder/vsphere/common/step_import_to_content_library.go index 1d91c27b..fba857d7 100644 --- a/builder/vsphere/common/step_import_to_content_library.go +++ b/builder/vsphere/common/step_import_to_content_library.go @@ -40,7 +40,6 @@ type ContentLibraryDestinationConfig struct { // Defaults to [cluster](#cluster). Cluster string `mapstructure:"cluster"` // Virtual machine folder into which the virtual machine template should be placed. - // This option is not used when importing OVF templates. // Defaults to the same folder as the source virtual machine. Folder string `mapstructure:"folder"` // Host onto which the virtual machine template should be placed. diff --git a/builder/vsphere/driver/vm.go b/builder/vsphere/driver/vm.go index 3dc46ea5..6f080df2 100644 --- a/builder/vsphere/driver/vm.go +++ b/builder/vsphere/driver/vm.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "io" "log" "net" "reflect" @@ -18,6 +19,7 @@ import ( "github.com/vmware/govmomi/property" "github.com/vmware/govmomi/vapi/vcenter" "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/soap" "github.com/vmware/govmomi/vim25/types" ) @@ -862,11 +864,86 @@ func (vm *VirtualMachineDriver) ImportOvfToContentLibrary(ovf vcenter.OVF) error ovf.Source.Type = "VirtualMachine" vcm := vcenter.NewManager(vm.driver.restClient.client) - _, err = vcm.CreateOVF(vm.driver.ctx, ovf) + itemID, err := vcm.CreateOVF(vm.driver.ctx, ovf) if err != nil { return err } + // Remove the NVRAM references in the ovf file if the vm version is 13 which means compatibility with 6.5 id required + datastoreID := l.library.Storage[0].DatastoreID + datastoreName, err := vm.driver.GetDatastoreName(datastoreID) + if err != nil { + log.Printf("[WARN] Couldn't find datastore name for library %s", l.library.Name) + return err + } + datastorePath := &object.DatastorePath{ + Datastore: datastoreName, + Path: fmt.Sprintf("contentlib-%s/%s", l.library.ID, itemID), + } + + ovfFileName := ovf.Spec.Name + ".ovf" + ovfFileActualName, err := vm.driver.GetDatastoreFilePath(datastoreID, datastorePath.String(), ovfFileName) + if err != nil { + log.Printf("[WARN] Couldn't find datastore ID path for %s\n", ovfFileName) + return fmt.Errorf("Error looking for %s in %s in datastore %s: %w", ovfFileName, datastorePath.String(), datastoreID, err) + } + ovfFilePath := datastorePath.Path + "/" + ovfFileActualName + log.Printf("Path to the ovf manifest in its datastore: [%s] %s\n", datastoreName, ovfFilePath) + + // Setup a datastore able to download and upload the ovf file we found + // it is required to configure it with its datacenter and its datastore name. + ref := types.ManagedObjectReference{Type: "Datastore", Value: datastoreID} + ds := object.NewDatastore(vm.driver.vimClient, ref) + ds.InventoryPath = "/" + datastoreName + ds.DatacenterPath = "-" + ancestors, err := mo.Ancestors(vm.driver.ctx, vm.driver.client, vm.driver.client.ServiceContent.PropertyCollector, ref) + if err != nil { + return err + } + for i := range ancestors { + if ancestors[i].Reference().Type == "Datacenter" { + ds.DatacenterPath = "/" + ancestors[i].Name + break + } + } + if ds.DatacenterPath == "-" { + return fmt.Errorf("Could not find a datacenter in the parents of %s", datastoreName) + } + f, _, err := ds.Download(vm.driver.ctx, ovfFilePath, &soap.DefaultDownload) + if err != nil { + log.Printf("[WARN] Couldn't download the %s", ovfFilePath) + return fmt.Errorf("Couldn't download the %s in folder %s from datastore %s: %w", ovfFilePath, datastorePath.Path, datastoreName, err) + } + b, err := io.ReadAll(f) + if err != nil { + log.Printf("[WARN] Couldn't read the downloaded %s", ovfFilePath) + return fmt.Errorf("Couldn't read the downloaded %s in folder %s from datastore %s: %w", ovfFileName, datastorePath.Path, datastoreName, err) + } + ovStr := string(b) + if !strings.Contains(ovStr, "vmx-13") { + log.Printf("No need to edit %s as its vm version is not '13'\n", ovfFilePath) + log.Printf("Publish to Content Library is completed\n") + return nil + } + log.Printf("Removing nvram references from [%s] %s as the vm version is '13'\n", datastoreName, ovfFilePath) + ovfLines := strings.Split(ovStr, "\n") + // now we must remove the 2 references to ovf: + // + // + var noNvramLines []string + for _, line := range ovfLines { + if strings.Contains(line, "vmw:key=\"nvram\"") || + (strings.Contains(line, ".nvram\"") && strings.Contains(line, "ovf:href=\"")) { + continue + } + noNvramLines = append(noNvramLines, line) + } + ovfStr := strings.Join(noNvramLines, "\n") + + if err = ds.Upload(vm.driver.ctx, strings.NewReader(ovfStr), ovfFilePath, &soap.DefaultUpload); err != nil { + return fmt.Errorf("Failed to upload %s in datastore %s as %s", ovfFileName, datastoreName, ovfFilePath) + } + return vm.driver.restClient.Logout(vm.driver.ctx) }