diff --git a/builder/nutanix/builder.go b/builder/nutanix/builder.go index 4b228d7..ab6eca7 100644 --- a/builder/nutanix/builder.go +++ b/builder/nutanix/builder.go @@ -85,7 +85,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) if imageUUID != nil { artifact := &Artifact{ Name: b.config.ImageName, - UUID: imageUUID.(string), + UUID: imageUUID.([]string)[0], } return artifact, nil } diff --git a/builder/nutanix/driver.go b/builder/nutanix/driver.go index e8cd9ff..9a299bb 100644 --- a/builder/nutanix/driver.go +++ b/builder/nutanix/driver.go @@ -31,7 +31,7 @@ type Driver interface { UploadImage(string, string, string, VmConfig) (*nutanixImage, error) DeleteImage(string) error GetImage(string) (*nutanixImage, error) - SaveVMDisk(string, []Category) (*nutanixImage, error) + SaveVMDisk(string, int, []Category) (*nutanixImage, error) WaitForShutdown(string, <-chan struct{}) bool } @@ -734,7 +734,7 @@ func (d *NutanixDriver) PowerOff(vmUUID string) error { log.Printf("PowerOff task: %s", taskUUID) return nil } -func (d *NutanixDriver) SaveVMDisk(diskUUID string, imageCategories []Category) (*nutanixImage, error) { +func (d *NutanixDriver) SaveVMDisk(diskUUID string, index int, imageCategories []Category) (*nutanixImage, error) { configCreds := client.Credentials{ URL: fmt.Sprintf("%s:%d", d.ClusterConfig.Endpoint, d.ClusterConfig.Port), @@ -750,10 +750,15 @@ func (d *NutanixDriver) SaveVMDisk(diskUUID string, imageCategories []Category) return nil, fmt.Errorf("error while NewV3Client, %s", err.Error()) } + name := d.Config.VmConfig.ImageName + if index > 0 { + name = fmt.Sprintf("%s-disk%d", name, index+1) + } + // When force_deregister, check if image already exists if d.Config.ForceDeregister { log.Println("force_deregister is set, check if image already exists") - ImageList, err := conn.V3.ListAllImage(fmt.Sprintf("name==%s", d.Config.VmConfig.ImageName)) + ImageList, err := conn.V3.ListAllImage(fmt.Sprintf("name==%s", name)) if err != nil { return nil, fmt.Errorf("error while ListAllImage, %s", err.Error()) } @@ -785,7 +790,7 @@ func (d *NutanixDriver) SaveVMDisk(diskUUID string, imageCategories []Category) req := &v3.ImageIntentInput{ Spec: &v3.Image{ - Name: &d.Config.VmConfig.ImageName, + Name: &name, Resources: &v3.ImageResources{ ImageType: StringPtr("DISK_IMAGE"), DataSourceReference: BuildReference(diskUUID, "vm_disk"), diff --git a/builder/nutanix/step_copy_image.go b/builder/nutanix/step_copy_image.go index 1e5dfd8..2654e13 100644 --- a/builder/nutanix/step_copy_image.go +++ b/builder/nutanix/step_copy_image.go @@ -19,35 +19,41 @@ func (s *stepCopyImage) Run(ctx context.Context, state multistep.StateBag) multi d := state.Get("driver").(Driver) vm, _ := d.GetVM(vmUUID) - ui.Say(fmt.Sprintf("Creating image from virtual machine %s...", s.Config.VMName)) + ui.Say(fmt.Sprintf("Creating image(s) from virtual machine %s...", s.Config.VMName)) // Choose disk to replicate - looking for first "DISK" - var diskToCopy string + var disksToCopy []string for i := range vm.nutanix.Spec.Resources.DiskList { if *vm.nutanix.Spec.Resources.DiskList[i].DeviceProperties.DeviceType == "DISK" { - diskToCopy = *vm.nutanix.Spec.Resources.DiskList[i].UUID + disksToCopy = append(disksToCopy, *vm.nutanix.Spec.Resources.DiskList[i].UUID) diskID := fmt.Sprintf("%s:%d", *vm.nutanix.Spec.Resources.DiskList[i].DeviceProperties.DiskAddress.AdapterType, *vm.nutanix.Spec.Resources.DiskList[i].DeviceProperties.DiskAddress.DeviceIndex) ui.Message("Found disk to copy: " + diskID) - break } } - if diskToCopy == "" { + if len(disksToCopy) == 0 { err := errors.New("no DISK was found to save, halting build") ui.Error(err.Error()) state.Put("error", err) return multistep.ActionHalt } - imageResponse, err := d.SaveVMDisk(diskToCopy, s.Config.ImageCategories) - if err != nil { - ui.Error("Image creation failed: " + err.Error()) - state.Put("error", err) - return multistep.ActionHalt + var imageList []string + + for i, diskToCopy := range disksToCopy { + + imageResponse, err := d.SaveVMDisk(diskToCopy, i, s.Config.ImageCategories) + if err != nil { + ui.Error("Image creation failed: " + err.Error()) + state.Put("error", err) + return multistep.ActionHalt + } + imageList = append(imageList, *imageResponse.image.Metadata.UUID) + ui.Message(fmt.Sprintf("Image successfully created: %s (%s)", *imageResponse.image.Spec.Name, *imageResponse.image.Metadata.UUID)) } - ui.Message(fmt.Sprintf("Successfully created image: %s (%s)", *imageResponse.image.Spec.Name, *imageResponse.image.Metadata.UUID)) - state.Put("image_uuid", (*imageResponse.image.Metadata.UUID)) + + state.Put("image_uuid", imageList) return multistep.ActionContinue } @@ -60,14 +66,17 @@ func (s *stepCopyImage) Cleanup(state multistep.StateBag) { } if imgUUID, ok := state.GetOk("image_uuid"); ok { - ui.Say(fmt.Sprintf("Deleting image %s...", s.Config.ImageName)) + ui.Say(fmt.Sprintf("Deleting image(s) %s...", s.Config.ImageName)) - err := d.DeleteImage(imgUUID.(string)) - if err != nil { - ui.Error("An error occurred while deleting image") - return - } else { - ui.Message("Image successfully deleted") + for _, image := range imgUUID.([]string) { + + err := d.DeleteImage(image) + if err != nil { + ui.Error("An error occurred while deleting image") + return + } else { + ui.Message(fmt.Sprintf("Image successfully deleted (%s)", image)) + } } } } diff --git a/test/e2e/centos-iso/scripts/ks.cfg b/test/e2e/centos-iso/scripts/ks.cfg index 93c8e9f..9016302 100644 --- a/test/e2e/centos-iso/scripts/ks.cfg +++ b/test/e2e/centos-iso/scripts/ks.cfg @@ -38,7 +38,8 @@ selinux --enforcing bootloader --location=mbr --boot-drive=sda # Setting up Logical Volume Manager and autopartitioning -clearpart --all --drives=sda --initlabel +clearpart --all --drives=sda,sdb --initlabel +ignoredisk --only-use=sda,sdb autopart --type=lvm # Eject cdrom and reboot diff --git a/test/e2e/centos-iso/source.pkr.hcl b/test/e2e/centos-iso/source.pkr.hcl index f4df7bc..c1a40c6 100644 --- a/test/e2e/centos-iso/source.pkr.hcl +++ b/test/e2e/centos-iso/source.pkr.hcl @@ -17,6 +17,11 @@ source "nutanix" "centos" { disk_size_gb = 40 } + vm_disks { + image_type = "DISK" + disk_size_gb = 20 + } + vm_nics { subnet_name = var.nutanix_subnet }