worked around deleting where an existing attachment on the same medium

This commit is contained in:
Adrian Cole 2012-01-06 09:53:06 -08:00
parent f7802b09b0
commit 66c49135eb
3 changed files with 127 additions and 11 deletions

View File

@ -19,12 +19,28 @@
package org.jclouds.virtualbox.functions; package org.jclouds.virtualbox.functions;
import com.google.common.base.Function; import static org.jclouds.virtualbox.util.MachineUtils.lockMachineAndApply;
import org.jclouds.virtualbox.domain.HardDisk; import static org.virtualbox_4_1.LockType.Write;
import org.virtualbox_4_1.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable; 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 * @author Mattias Holmqvist
*/ */
@ -37,6 +53,7 @@ public class CreateMediumIfNotAlreadyExists implements Function<HardDisk, IMediu
this.manager = manager; this.manager = manager;
this.overwriteIfExists = overwriteIfExists; this.overwriteIfExists = overwriteIfExists;
} }
public static final Pattern ATTACHED_PATTERN = Pattern.compile(".*is still attached.*: ([-0-9a-f]+) .*");
@Override @Override
public IMedium apply(@Nullable HardDisk hardDisk) { public IMedium apply(@Nullable HardDisk hardDisk) {
@ -45,8 +62,11 @@ public class CreateMediumIfNotAlreadyExists implements Function<HardDisk, IMediu
String diskPath = hardDisk.getDiskPath(); String diskPath = hardDisk.getDiskPath();
final IMedium medium = vBox.findMedium(diskPath, DeviceType.HardDisk); final IMedium medium = vBox.findMedium(diskPath, DeviceType.HardDisk);
if (overwriteIfExists) { if (overwriteIfExists) {
final IProgress progress = medium.deleteStorage(); try {
progress.waitForCompletion(-1); deleteMediumAndBlockUntilComplete(medium);
} catch (VBoxException e){
onAlreadyAttachedExceptionDetachOrPropagate(vBox, medium, e);
}
return createNewMedium(vBox, hardDisk); return createNewMedium(vBox, hardDisk);
} else { } else {
throw new IllegalStateException("Medium for path " + diskPath + " already exists."); throw new IllegalStateException("Medium for path " + diskPath + " already exists.");
@ -58,6 +78,29 @@ public class CreateMediumIfNotAlreadyExists implements Function<HardDisk, IMediu
} }
} }
private void onAlreadyAttachedExceptionDetachOrPropagate(IVirtualBox vBox, final IMedium medium, VBoxException e) {
Matcher matcher = ATTACHED_PATTERN.matcher(e.getMessage());
if (matcher.find()) {
String machineId = matcher.group(1);
IMachine immutableMachine = vBox.findMachine(machineId);
IMediumAttachment mediumAttachment = Iterables.find(immutableMachine.getMediumAttachments(), new Predicate<IMediumAttachment>(){
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) { private IMedium createNewMedium(IVirtualBox vBox, HardDisk hardDisk) {
IMedium medium = vBox.createHardDisk(hardDisk.getDiskFormat(), hardDisk.getDiskPath()); IMedium medium = vBox.createHardDisk(hardDisk.getDiskFormat(), hardDisk.getDiskPath());
createBaseStorage(medium); createBaseStorage(medium);

View File

@ -32,19 +32,20 @@ import com.google.common.base.Function;
public class DetachDistroMediumFromMachine implements Function<IMachine, Void> { public class DetachDistroMediumFromMachine implements Function<IMachine, Void> {
private final String controller; private final String controller;
private int controllerPort; private int port;
private int device; private int deviceSlot;
public DetachDistroMediumFromMachine(String controller, int controllerPort, int device) { public DetachDistroMediumFromMachine(String controller, int port, int deviceSlot) {
this.controller = controller; this.controller = controller;
this.controllerPort = controllerPort; this.port = port;
this.device = device; this.deviceSlot = deviceSlot;
} }
//TODO: should this be a function on HardDisk?
@Override @Override
public Void apply(@Nullable IMachine machine) { public Void apply(@Nullable IMachine machine) {
try { try {
machine.detachDevice(controller, controllerPort, device); machine.detachDevice(controller, port, deviceSlot);
machine.saveSettings(); machine.saveSettings();
} catch (VBoxException e) { } catch (VBoxException e) {
if (!alreadyDetached(e)) if (!alreadyDetached(e))

View File

@ -34,11 +34,16 @@ import org.testng.annotations.Test;
import org.virtualbox_4_1.DeviceType; import org.virtualbox_4_1.DeviceType;
import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IMedium; import org.virtualbox_4_1.IMedium;
import org.virtualbox_4_1.IMediumAttachment;
import org.virtualbox_4_1.IProgress; import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.IVirtualBox; import org.virtualbox_4_1.IVirtualBox;
import org.virtualbox_4_1.LockType;
import org.virtualbox_4_1.VBoxException; import org.virtualbox_4_1.VBoxException;
import org.virtualbox_4_1.VirtualBoxManager; import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.collect.ImmutableList;
/** /**
* @author Mattias Holmqvist * @author Mattias Holmqvist
*/ */
@ -114,6 +119,73 @@ public class CreateMediumIfNotAlreadyExistsTest {
assertNotSame(newDisk, medium); 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) @Test(expectedExceptions = IllegalStateException.class)
public void testFailWhenMediumExistsAndNotUsingOverwrite() throws Exception { public void testFailWhenMediumExistsAndNotUsingOverwrite() throws Exception {
HardDisk hardDisk = createTestHardDisk(); HardDisk hardDisk = createTestHardDisk();