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 new file mode 100644 index 0000000000..afef1a6d69 --- /dev/null +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateMediumIfNotAlreadyExists.java @@ -0,0 +1,99 @@ +/* + * * + * * Licensed to jclouds, Inc. (jclouds) under one or more + * * contributor license agreements. See the NOTICE file + * * distributed with this work for additional information + * * regarding copyright ownership. jclouds licenses this file + * * to you under the Apache License, Version 2.0 (the + * * "License"); you may not use this file except in compliance + * * with the License. You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, + * * software distributed under the License is distributed on an + * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * * KIND, either express or implied. See the License for the + * * specific language governing permissions and limitations + * * under the License. + * + */ + +package org.jclouds.virtualbox.functions; + +import com.google.common.base.Function; +import org.virtualbox_4_1.*; + +import javax.annotation.Nullable; + +/** + * @author Mattias Holmqvist + */ +public class CreateMediumIfNotAlreadyExists implements Function { + + private final VirtualBoxManager manager; + private final String diskFormat; + private boolean overwriteIfExists; + + public CreateMediumIfNotAlreadyExists(VirtualBoxManager manager, String diskFormat, boolean overwriteIfExists) { + this.manager = manager; + this.diskFormat = diskFormat; + this.overwriteIfExists = overwriteIfExists; + } + + @Override + public IMedium apply(@Nullable String path) { + IVirtualBox vBox = manager.getVBox(); + try { + final IMedium medium = vBox.findMedium(path, DeviceType.HardDisk); + if (overwriteIfExists) { + final IProgress progress = medium.deleteStorage(); + progress.waitForCompletion(-1); + return createNewMedium(vBox, path); + } else { + throw new IllegalStateException("Medium for path " + path + " already exists."); + } + } catch (VBoxException e) { + if (notFoundException(e)) + return createNewMedium(vBox, path); + throw e; + } + } + + private IMedium createNewMedium(IVirtualBox vBox, String path) { + IMedium hardDisk = vBox.createHardDisk(diskFormat, path); + createBaseStorage(hardDisk); + return hardDisk; + } + + private boolean notFoundException(VBoxException e) { + return e.getMessage().indexOf("Could not find an open hard disk with location ") != -1; + } + + private void createBaseStorage(IMedium hardDisk) { + try { + long size = 4L * 1024L * 1024L * 1024L - 4L; + IProgress storageCreation = hardDisk.createBaseStorage(size, (long) org.virtualbox_4_1.jaxws.MediumVariant.STANDARD.ordinal()); + storageCreation.waitForCompletion(-1); + } catch (VBoxException e) { + if (fileNotFoundException(e)) { + // File for medium could not be found. Something wrong with creation. + hardDisk.deleteStorage(); + } + if (!storageAlreadyExists(e)) { + // Hard disk file was created but the storage had been created before that. + throw e; + } + } + } + + private boolean fileNotFoundException(VBoxException e) { + return e.getMessage().indexOf("VERR_FILE_NOT_FOUND") != -1; + } + + private boolean storageAlreadyExists(VBoxException e) { + return e.getMessage().indexOf("VirtualBox error: Storage for the medium ") != -1 && + e.getMessage().indexOf("is already created") != -1; + } + +} diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IsoToIMachine.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IsoToIMachine.java index f7b055f43d..fb410a44a7 100644 --- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IsoToIMachine.java +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IsoToIMachine.java @@ -1,23 +1,4 @@ -/* - * * - * * Licensed to jclouds, Inc. (jclouds) under one or more - * * contributor license agreements. See the NOTICE file - * * distributed with this work for additional information - * * regarding copyright ownership. jclouds licenses this file - * * to you under the Apache License, Version 2.0 (the - * * "License"); you may not use this file except in compliance - * * with the License. You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, - * * software distributed under the License is distributed on an - * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * * KIND, either express or implied. See the License for the - * * specific language governing permissions and limitations - * * under the License. - * - */ + package org.jclouds.virtualbox.functions; @@ -35,6 +16,7 @@ import static org.virtualbox_4_1.NATProtocol.TCP; import static org.virtualbox_4_1.NetworkAttachmentType.NAT; import java.io.File; +import java.util.List; import javax.annotation.Resource; import javax.inject.Named; @@ -51,15 +33,7 @@ import org.jclouds.ssh.SshException; import org.jclouds.virtualbox.config.VirtualBoxConstants; import org.jclouds.virtualbox.functions.admin.StartJettyIfNotAlreadyRunning; import org.jclouds.virtualbox.settings.KeyboardScancodes; -import org.virtualbox_4_1.AccessMode; -import org.virtualbox_4_1.DeviceType; -import org.virtualbox_4_1.IMachine; -import org.virtualbox_4_1.IMedium; -import org.virtualbox_4_1.IProgress; -import org.virtualbox_4_1.ISession; -import org.virtualbox_4_1.LockType; -import org.virtualbox_4_1.VBoxException; -import org.virtualbox_4_1.VirtualBoxManager; +import org.virtualbox_4_1.*; import com.google.common.base.Function; import com.google.inject.Inject; @@ -140,14 +114,12 @@ public class IsoToIMachine implements Function { new File(adminDiskPath).delete(); } - final IMedium hd = manager.getVBox().createHardDisk(diskFormat, adminDiskPath); - long size = 4L * 1024L * 1024L * 1024L - 4L; - IProgress storageCreation = hd.createBaseStorage(size, (long) org.virtualbox_4_1.jaxws.MediumVariant.STANDARD.ordinal()); - storageCreation.waitForCompletion(-1); + // Create hard disk + IMedium hardDisk = new CreateMediumIfNotAlreadyExists(manager, diskFormat, true).apply(adminDiskPath); // Attach hard disk to machine lockMachineAndApply(manager, Write, vmName, - new AttachHardDiskToMachineIfNotAlreadyAttached(controllerIDE, hd, manager)); + new AttachHardDiskToMachineIfNotAlreadyAttached(controllerIDE, hardDisk, manager)); // NAT lockMachineAndApply(manager, Write, vmName, new Function() { 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 new file mode 100644 index 0000000000..d7537a58af --- /dev/null +++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateMediumIfNotAlreadyExistsTest.java @@ -0,0 +1,143 @@ +/* + * * + * * Licensed to jclouds, Inc. (jclouds) under one or more + * * contributor license agreements. See the NOTICE file + * * distributed with this work for additional information + * * regarding copyright ownership. jclouds licenses this file + * * to you under the Apache License, Version 2.0 (the + * * "License"); you may not use this file except in compliance + * * with the License. You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, + * * software distributed under the License is distributed on an + * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * * KIND, either express or implied. See the License for the + * * specific language governing permissions and limitations + * * under the License. + * + */ + +package org.jclouds.virtualbox.functions; + +import org.testng.annotations.Test; +import org.virtualbox_4_1.*; + +import static org.easymock.EasyMock.anyLong; +import static org.easymock.EasyMock.expect; +import static org.easymock.classextension.EasyMock.*; +import static org.testng.Assert.assertNotSame; + +/** + * @author Mattias Holmqvist + */ +public class CreateMediumIfNotAlreadyExistsTest { + + @Test + public void testCreateMediumWhenDiskDoesNotExists() throws Exception { + String adminDiskPath = "/Users/johndoe/jclouds-virtualbox-images/admin.vdi"; + String diskFormat = "vdi"; + + VirtualBoxManager manager = createNiceMock(VirtualBoxManager.class); + IMachine machine = createMock(IMachine.class); + IVirtualBox vBox = createMock(IVirtualBox.class); + IMedium hardDisk = createMock(IMedium.class); + IProgress progress = createNiceMock(IProgress.class); + + StringBuilder errorBuilder = new StringBuilder(); + errorBuilder.append("org.virtualbox_4_1.VBoxException: VirtualBox error: "); + errorBuilder.append("Could not find an open hard disk with location "); + errorBuilder.append("'/Users/johndoe/jclouds-virtualbox-test/testadmin.vdi' (0x80BB0001)"); + String errorMessage = errorBuilder.toString(); + + expect(manager.getVBox()).andReturn(vBox).anyTimes(); + + VBoxException notFoundException = new VBoxException(createNiceMock(Throwable.class), errorMessage); + expect(vBox.findMedium(adminDiskPath, DeviceType.HardDisk)).andThrow(notFoundException); + expect(vBox.createHardDisk(diskFormat, adminDiskPath)).andReturn(hardDisk); + expect(hardDisk.createBaseStorage(anyLong(), anyLong())).andReturn(progress); + + replay(manager, machine, vBox, hardDisk); + + new CreateMediumIfNotAlreadyExists(manager, diskFormat, true).apply(adminDiskPath); + + verify(machine, vBox); + + } + + @Test + public void testDeleteAndCreateNewStorageWhenMediumExistsAndUsingOverwrite() throws Exception { + String adminDiskPath = "/Users/johndoe/jclouds-virtualbox-images/admin.vdi"; + String diskFormat = "vdi"; + + VirtualBoxManager manager = createNiceMock(VirtualBoxManager.class); + IMachine machine = createMock(IMachine.class); + IVirtualBox vBox = createMock(IVirtualBox.class); + IMedium hardDisk = 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(hardDisk); + + expect(hardDisk.deleteStorage()).andReturn(progress); + expect(vBox.createHardDisk(diskFormat, adminDiskPath)).andReturn(newHardDisk); + expect(newHardDisk.createBaseStorage(anyLong(), anyLong())).andReturn(progress); + + replay(manager, machine, vBox, hardDisk, newHardDisk, progress); + + IMedium newDisk = new CreateMediumIfNotAlreadyExists(manager, diskFormat, true).apply(adminDiskPath); + + verify(machine, vBox, hardDisk); + assertNotSame(newDisk, hardDisk); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testFailWhenMediumExistsAndNotUsingOverwrite() throws Exception { + String adminDiskPath = "/Users/johndoe/jclouds-virtualbox-images/admin.vdi"; + String diskFormat = "vdi"; + + VirtualBoxManager manager = createNiceMock(VirtualBoxManager.class); + IMachine machine = createMock(IMachine.class); + IVirtualBox vBox = createMock(IVirtualBox.class); + IMedium hardDisk = 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(hardDisk); + + replay(manager, machine, vBox, hardDisk, newHardDisk, progress); + + new CreateMediumIfNotAlreadyExists(manager, diskFormat, false).apply(adminDiskPath); + } + + @Test(expectedExceptions = VBoxException.class) + public void testFailOnOtherVBoxException() throws Exception { + + String adminDiskPath = "/Users/johndoe/jclouds-virtualbox-images/admin.vdi"; + String diskFormat = "vdi"; + + VirtualBoxManager manager = createNiceMock(VirtualBoxManager.class); + IMachine machine = createMock(IMachine.class); + IVirtualBox vBox = createMock(IVirtualBox.class); + IMedium hardDisk = createMock(IMedium.class); + IProgress progress = createNiceMock(IProgress.class); + + String errorMessage = "VirtualBox error: Some other VBox error"; + + expect(manager.getVBox()).andReturn(vBox).anyTimes(); + + VBoxException notFoundException = new VBoxException(createNiceMock(Throwable.class), errorMessage); + expect(vBox.findMedium(adminDiskPath, DeviceType.HardDisk)).andThrow(notFoundException); + expect(vBox.createHardDisk(diskFormat, adminDiskPath)).andReturn(hardDisk); + expect(hardDisk.createBaseStorage(anyLong(), anyLong())).andReturn(progress); + + replay(manager, machine, vBox, hardDisk); + + new CreateMediumIfNotAlreadyExists(manager, diskFormat, true).apply(adminDiskPath); + } + + +}