mirror of https://github.com/apache/jclouds.git
worked around deleting where an existing attachment on the same medium
This commit is contained in:
parent
f7802b09b0
commit
66c49135eb
|
@ -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<HardDisk, IMediu
|
|||
this.manager = manager;
|
||||
this.overwriteIfExists = overwriteIfExists;
|
||||
}
|
||||
public static final Pattern ATTACHED_PATTERN = Pattern.compile(".*is still attached.*: ([-0-9a-f]+) .*");
|
||||
|
||||
@Override
|
||||
public IMedium apply(@Nullable HardDisk hardDisk) {
|
||||
|
@ -45,8 +62,11 @@ public class CreateMediumIfNotAlreadyExists implements Function<HardDisk, IMediu
|
|||
String diskPath = hardDisk.getDiskPath();
|
||||
final IMedium medium = vBox.findMedium(diskPath, DeviceType.HardDisk);
|
||||
if (overwriteIfExists) {
|
||||
final IProgress progress = medium.deleteStorage();
|
||||
progress.waitForCompletion(-1);
|
||||
try {
|
||||
deleteMediumAndBlockUntilComplete(medium);
|
||||
} catch (VBoxException e){
|
||||
onAlreadyAttachedExceptionDetachOrPropagate(vBox, medium, e);
|
||||
}
|
||||
return createNewMedium(vBox, hardDisk);
|
||||
} else {
|
||||
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) {
|
||||
IMedium medium = vBox.createHardDisk(hardDisk.getDiskFormat(), hardDisk.getDiskPath());
|
||||
createBaseStorage(medium);
|
||||
|
|
|
@ -32,19 +32,20 @@ import com.google.common.base.Function;
|
|||
public class DetachDistroMediumFromMachine implements Function<IMachine, Void> {
|
||||
|
||||
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))
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue