diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateMediumIfNotAlreadyExists.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateMediumIfNotAlreadyExists.java index c8a45ca606..46fa820079 100644 --- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateMediumIfNotAlreadyExists.java +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateMediumIfNotAlreadyExists.java @@ -19,12 +19,28 @@ package org.jclouds.virtualbox.functions; -import com.google.common.base.Function; -import org.jclouds.virtualbox.domain.HardDisk; -import org.virtualbox_4_1.*; +import static org.jclouds.virtualbox.util.MachineUtils.lockMachineAndApply; +import static org.virtualbox_4_1.LockType.Write; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.annotation.Nullable; +import org.jclouds.virtualbox.domain.HardDisk; +import org.virtualbox_4_1.DeviceType; +import org.virtualbox_4_1.IMachine; +import org.virtualbox_4_1.IMedium; +import org.virtualbox_4_1.IMediumAttachment; +import org.virtualbox_4_1.IProgress; +import org.virtualbox_4_1.IVirtualBox; +import org.virtualbox_4_1.VBoxException; +import org.virtualbox_4_1.VirtualBoxManager; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; + /** * @author Mattias Holmqvist */ @@ -37,6 +53,7 @@ public class CreateMediumIfNotAlreadyExists implements Function(){ + public boolean apply(IMediumAttachment in){ + return in.getMedium().getId().equals(medium.getId()); + } + }); + lockMachineAndApply(manager, Write, immutableMachine.getName(), new DetachDistroMediumFromMachine( + mediumAttachment.getController(), mediumAttachment.getPort(), mediumAttachment.getDevice())); + deleteMediumAndBlockUntilComplete(medium); + } else { + throw e; + } + } + + void deleteMediumAndBlockUntilComplete(IMedium medium){ + final IProgress progress = medium.deleteStorage(); + progress.waitForCompletion(-1); + } + private IMedium createNewMedium(IVirtualBox vBox, HardDisk hardDisk) { IMedium medium = vBox.createHardDisk(hardDisk.getDiskFormat(), hardDisk.getDiskPath()); createBaseStorage(medium); diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/DetachDistroMediumFromMachine.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/DetachDistroMediumFromMachine.java index 827dff0b52..46ea0bbbc7 100644 --- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/DetachDistroMediumFromMachine.java +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/DetachDistroMediumFromMachine.java @@ -32,19 +32,20 @@ import com.google.common.base.Function; public class DetachDistroMediumFromMachine implements Function { private final String controller; - private int controllerPort; - private int device; + private int port; + private int deviceSlot; - public DetachDistroMediumFromMachine(String controller, int controllerPort, int device) { + public DetachDistroMediumFromMachine(String controller, int port, int deviceSlot) { this.controller = controller; - this.controllerPort = controllerPort; - this.device = device; + this.port = port; + this.deviceSlot = deviceSlot; } + //TODO: should this be a function on HardDisk? @Override public Void apply(@Nullable IMachine machine) { try { - machine.detachDevice(controller, controllerPort, device); + machine.detachDevice(controller, port, deviceSlot); machine.saveSettings(); } catch (VBoxException e) { if (!alreadyDetached(e)) diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateMediumIfNotAlreadyExistsTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateMediumIfNotAlreadyExistsTest.java index 5952faf144..d0e5c88896 100644 --- a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateMediumIfNotAlreadyExistsTest.java +++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateMediumIfNotAlreadyExistsTest.java @@ -34,11 +34,16 @@ import org.testng.annotations.Test; import org.virtualbox_4_1.DeviceType; import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.IMedium; +import org.virtualbox_4_1.IMediumAttachment; import org.virtualbox_4_1.IProgress; +import org.virtualbox_4_1.ISession; import org.virtualbox_4_1.IVirtualBox; +import org.virtualbox_4_1.LockType; import org.virtualbox_4_1.VBoxException; import org.virtualbox_4_1.VirtualBoxManager; +import com.google.common.collect.ImmutableList; + /** * @author Mattias Holmqvist */ @@ -114,6 +119,73 @@ public class CreateMediumIfNotAlreadyExistsTest { assertNotSame(newDisk, medium); } + @Test + public void testDeleteAndCreateNewStorageWhenMediumExistsAndUsingOverwriteAndStillAttachedDetachesOldThing() throws Exception { + HardDisk hardDisk = createTestHardDisk(); + + VirtualBoxManager manager = createNiceMock(VirtualBoxManager.class); + IMachine machine = createMock(IMachine.class); + IVirtualBox vBox = createMock(IVirtualBox.class); + IMedium medium = createMock(IMedium.class); + + IMedium newHardDisk = createMock(IMedium.class); + IProgress progress = createNiceMock(IProgress.class); + + expect(manager.getVBox()).andReturn(vBox).anyTimes(); + expect(vBox.findMedium(adminDiskPath, DeviceType.HardDisk)).andReturn(medium); + + + String oldMachineId = "a1e03931-29f3-4370-ada3-9547b1009212"; + String oldMachineName = "oldMachine"; + IMachine oldMachine = createMock(IMachine.class); + IMediumAttachment oldAttachment = createMock(IMediumAttachment.class); + String oldAttachmentController = "oldAttachmentController"; + int oldAttachmentDevice = 1; + int oldAttachmentPort = 2; + IMedium oldMedium = createMock(IMedium.class); + String oldMediumId = "oldMediumId"; + ISession detachSession = createNiceMock(ISession.class); + + StringBuilder errorBuilder = new StringBuilder(); + errorBuilder.append("org.virtualbox_4_1.VBoxException: VirtualBox error: "); + errorBuilder.append("Cannot delete storage: medium '/Users/adriancole/jclouds-virtualbox-test/testadmin.vdi "); + errorBuilder.append("is still attached to the following 1 virtual machine(s): "); + errorBuilder.append(oldMachineId + " (0x80BB000C)"); + String errorMessage = errorBuilder.toString(); + + VBoxException stillAttached = new VBoxException(createNiceMock(Throwable.class), errorMessage); + expect(medium.deleteStorage()).andThrow(stillAttached); + + expect(vBox.findMachine(oldMachineId)).andReturn(oldMachine); + expect(oldMachine.getMediumAttachments()).andReturn(ImmutableList.of(oldAttachment)); + expect(oldAttachment.getMedium()).andReturn(oldMedium); + expect(oldMedium.getId()).andReturn(oldMediumId); + // in this case, they are the same medium, so safe to detach + expect(medium.getId()).andReturn(oldMediumId); + expect(oldMachine.getName()).andReturn(oldMachineName); + expect(oldAttachment.getController()).andReturn(oldAttachmentController); + expect(oldAttachment.getDevice()).andReturn(oldAttachmentDevice); + expect(oldAttachment.getPort()).andReturn(oldAttachmentPort); + // TODO: is this ok that we searched by ID last time? + expect(vBox.findMachine(oldMachineName)).andReturn(oldMachine); + expect(manager.getSessionObject()).andReturn(detachSession); + oldMachine.lockMachine(detachSession, LockType.Write); + expect(detachSession.getMachine()).andReturn(oldMachine); + oldMachine.detachDevice(oldAttachmentController, oldAttachmentPort, oldAttachmentDevice); + oldMachine.saveSettings(); + + expect(medium.deleteStorage()).andReturn(progress); + expect(vBox.createHardDisk(diskFormat, adminDiskPath)).andReturn(newHardDisk); + expect(newHardDisk.createBaseStorage(anyLong(), anyLong())).andReturn(progress); + + replay(manager,oldMachine, oldAttachment,oldMedium, detachSession, machine, vBox, medium, newHardDisk, progress); + + IMedium newDisk = new CreateMediumIfNotAlreadyExists(manager, true).apply(hardDisk); + + verify(machine,oldMachine,oldAttachment, detachSession, oldMedium, vBox, medium); + assertNotSame(newDisk, medium); + } + @Test(expectedExceptions = IllegalStateException.class) public void testFailWhenMediumExistsAndNotUsingOverwrite() throws Exception { HardDisk hardDisk = createTestHardDisk();