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;
|
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);
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue