mirror of https://github.com/apache/jclouds.git
started refactoring IsoToIMachine to re-use error handling
This commit is contained in:
parent
aab1290b85
commit
926989c5f1
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* 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 static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import org.virtualbox_4_1.IMachine;
|
||||
import org.virtualbox_4_1.StorageBus;
|
||||
import org.virtualbox_4_1.VBoxException;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
public class AddIDEControllerIfNotExists implements Function<IMachine, Void> {
|
||||
private final String controllerName;
|
||||
|
||||
public AddIDEControllerIfNotExists(String controllerName) {
|
||||
this.controllerName = checkNotNull(controllerName, "controllerName");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void apply(IMachine arg0) {
|
||||
try {
|
||||
arg0.addStorageController(controllerName, StorageBus.IDE);
|
||||
arg0.saveSettings();
|
||||
} catch (VBoxException e) {
|
||||
if (e.getMessage().indexOf("already exists") == -1)
|
||||
throw e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("addStorageController(%s, IDE)", controllerName);
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
package org.jclouds.virtualbox.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
|
||||
import static org.jclouds.compute.options.RunScriptOptions.Builder.wrapInInitScript;
|
||||
|
@ -28,6 +29,7 @@ import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTA
|
|||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_WORKINGDIR;
|
||||
import static org.virtualbox_4_1.AccessMode.ReadOnly;
|
||||
import static org.virtualbox_4_1.DeviceType.DVD;
|
||||
import static org.virtualbox_4_1.LockType.Shared;
|
||||
import static org.virtualbox_4_1.LockType.Write;
|
||||
import static org.virtualbox_4_1.NATProtocol.TCP;
|
||||
import static org.virtualbox_4_1.NetworkAttachmentType.NAT;
|
||||
|
@ -37,11 +39,7 @@ import java.io.File;
|
|||
import javax.annotation.Resource;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.eclipse.jetty.server.handler.ResourceHandler;
|
||||
import org.jclouds.compute.ComputeServiceContext;
|
||||
import org.jclouds.compute.domain.ExecResponse;
|
||||
import org.jclouds.compute.options.RunScriptOptions;
|
||||
|
@ -60,14 +58,13 @@ 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.StorageBus;
|
||||
import org.virtualbox_4_1.VBoxException;
|
||||
import org.virtualbox_4_1.VirtualBoxManager;
|
||||
import org.virtualbox_4_1.jaxws.MediumVariant;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
|
||||
public class IsoToIMachine implements Function<String, IMachine> {
|
||||
|
||||
@Resource
|
||||
|
@ -89,19 +86,9 @@ public class IsoToIMachine implements Function<String, IMachine> {
|
|||
private Credentials credentials;
|
||||
|
||||
@Inject
|
||||
public IsoToIMachine(VirtualBoxManager manager,
|
||||
String adminDisk,
|
||||
String diskFormat,
|
||||
String settingsFile,
|
||||
String vmName,
|
||||
String osTypeId,
|
||||
String vmId,
|
||||
boolean forceOverwrite,
|
||||
String controllerIDE,
|
||||
ComputeServiceContext context,
|
||||
String hostId,
|
||||
String guestId,
|
||||
Credentials credentials) {
|
||||
public IsoToIMachine(VirtualBoxManager manager, String adminDisk, String diskFormat, String settingsFile,
|
||||
String vmName, String osTypeId, String vmId, boolean forceOverwrite, String controllerIDE,
|
||||
ComputeServiceContext context, String hostId, String guestId, Credentials credentials) {
|
||||
super();
|
||||
this.manager = manager;
|
||||
this.adminDisk = adminDisk;
|
||||
|
@ -130,70 +117,92 @@ public class IsoToIMachine implements Function<String, IMachine> {
|
|||
|
||||
String defaultWorkingDir = System.getProperty("user.home") + "/jclouds-virtualbox-test";
|
||||
String workingDir = System.getProperty(VIRTUALBOX_WORKINGDIR, defaultWorkingDir);
|
||||
IMedium distroMedium = manager.getVBox().openMedium(workingDir + "/" + isoName, DVD, ReadOnly, forceOverwrite);
|
||||
|
||||
// Change RAM
|
||||
Long memorySize = new Long(1024);
|
||||
ISession session = manager.getSessionObject();
|
||||
IMachine machine = manager.getVBox().findMachine(vmName);
|
||||
machine.lockMachine(session, Write);
|
||||
IMachine mutable = session.getMachine();
|
||||
mutable.setMemorySize(memorySize);
|
||||
mutable.saveSettings();
|
||||
session.unlockMachine();
|
||||
lockMachineAndApply(manager, Write, vmName, new Function<IMachine, Void>() {
|
||||
|
||||
@Override
|
||||
public Void apply(IMachine arg0) {
|
||||
arg0.setMemorySize(1024l);
|
||||
arg0.saveSettings();
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// IDE Controller
|
||||
machine.lockMachine(session, Write);
|
||||
mutable = session.getMachine();
|
||||
mutable.addStorageController(controllerIDE, StorageBus.IDE);
|
||||
mutable.saveSettings();
|
||||
session.unlockMachine();
|
||||
ensureMachineHasIDEControllerNamed(vmName, controllerIDE);
|
||||
|
||||
// DISK
|
||||
String adminDiskPath = workingDir + "/" + adminDisk;
|
||||
if (new File(adminDiskPath).exists()) {
|
||||
new File(adminDiskPath).delete();
|
||||
}
|
||||
IMedium hd = manager.getVBox().createHardDisk(diskFormat, adminDiskPath);
|
||||
|
||||
final IMedium distroMedium = manager.getVBox().openMedium(workingDir + "/" + isoName, DVD, ReadOnly,
|
||||
forceOverwrite);
|
||||
|
||||
lockMachineAndApply(manager, Write, vmName, new Function<IMachine, Void>() {
|
||||
|
||||
@Override
|
||||
public Void apply(IMachine arg0) {
|
||||
try {
|
||||
arg0.attachDevice(controllerIDE, 0, 0, DeviceType.DVD, distroMedium);
|
||||
arg0.saveSettings();
|
||||
} catch (VBoxException e) {
|
||||
if (e.getMessage().indexOf("is already attached to port") == -1)
|
||||
throw e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Create and attach hard disk
|
||||
final IMedium hd = manager.getVBox().createHardDisk(diskFormat, adminDiskPath);
|
||||
long size = 4L * 1024L * 1024L * 1024L - 4L;
|
||||
IProgress storageCreation = hd.createBaseStorage(size, (long) MediumVariant.STANDARD.ordinal());
|
||||
storageCreation.waitForCompletion(-1);
|
||||
|
||||
machine.lockMachine(session, Write);
|
||||
mutable = session.getMachine();
|
||||
mutable.attachDevice(controllerIDE, 0, 0, DeviceType.DVD, distroMedium);
|
||||
mutable.saveSettings();
|
||||
session.unlockMachine();
|
||||
lockMachineAndApply(manager, Write, vmName, new Function<IMachine, Void>() {
|
||||
|
||||
// Create and attach hard disk
|
||||
machine.lockMachine(session, Write);
|
||||
mutable = session.getMachine();
|
||||
mutable.attachDevice(controllerIDE, 0, 1, DeviceType.HardDisk, hd);
|
||||
mutable.saveSettings();
|
||||
session.unlockMachine();
|
||||
@Override
|
||||
public Void apply(IMachine arg0) {
|
||||
arg0.attachDevice(controllerIDE, 0, 1, DeviceType.HardDisk, hd);
|
||||
arg0.saveSettings();
|
||||
return null;
|
||||
}
|
||||
|
||||
// NIC
|
||||
machine.lockMachine(session, Write);
|
||||
mutable = session.getMachine();
|
||||
});
|
||||
|
||||
// NAT
|
||||
mutable.getNetworkAdapter(0l).setAttachmentType(NAT);
|
||||
machine.getNetworkAdapter(0l)
|
||||
.getNatDriver()
|
||||
.addRedirect("guestssh", TCP, "127.0.0.1", 2222, "", 22);
|
||||
mutable.getNetworkAdapter(0l).setEnabled(true);
|
||||
mutable.saveSettings();
|
||||
session.unlockMachine();
|
||||
lockMachineAndApply(manager, Write, vmName, new Function<IMachine, Void>() {
|
||||
|
||||
@Override
|
||||
public Void apply(IMachine arg0) {
|
||||
arg0.getNetworkAdapter(0l).setAttachmentType(NAT);
|
||||
arg0.getNetworkAdapter(0l).getNatDriver().addRedirect("guestssh", TCP, "127.0.0.1", 2222, "", 22);
|
||||
arg0.getNetworkAdapter(0l).setEnabled(true);
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
String guestAdditionsDvd = workingDir + "/VBoxGuestAdditions_4.1.2.iso";
|
||||
IMedium guestAdditionsDvdMedium = manager.getVBox().openMedium(guestAdditionsDvd, DeviceType.DVD, AccessMode.ReadOnly, forceOverwrite);
|
||||
machine.lockMachine(session, Write);
|
||||
mutable = session.getMachine();
|
||||
mutable.attachDevice(controllerIDE, 1, 1, DeviceType.DVD, guestAdditionsDvdMedium);
|
||||
mutable.saveSettings();
|
||||
session.unlockMachine();
|
||||
final IMedium guestAdditionsDvdMedium = manager.getVBox().openMedium(guestAdditionsDvd, DeviceType.DVD,
|
||||
AccessMode.ReadOnly, forceOverwrite);
|
||||
|
||||
IProgress prog = machine.launchVMProcess(session, "gui", "");
|
||||
lockMachineAndApply(manager, Write, vmName, new Function<IMachine, Void>() {
|
||||
|
||||
@Override
|
||||
public Void apply(IMachine arg0) {
|
||||
arg0.attachDevice(controllerIDE, 1, 1, DeviceType.DVD, guestAdditionsDvdMedium);
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
IProgress prog = vm.launchVMProcess(manager.getSessionObject(), "gui", "");
|
||||
prog.waitForCompletion(-1);
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
|
@ -203,7 +212,6 @@ public class IsoToIMachine implements Function<String, IMachine> {
|
|||
|
||||
String installKeySequence = System.getProperty(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE, defaultInstallSequence());
|
||||
sendKeyboardSequence(installKeySequence);
|
||||
session.unlockMachine();
|
||||
|
||||
boolean sshDeamonIsRunning = false;
|
||||
while (!sshDeamonIsRunning) {
|
||||
|
@ -218,12 +226,16 @@ public class IsoToIMachine implements Function<String, IMachine> {
|
|||
}
|
||||
|
||||
logger.debug("Installation of image complete. Powering down...");
|
||||
lockSessionOnMachineAndApply(manager, Shared, vmName, new Function<ISession, Void>() {
|
||||
|
||||
machine.lockMachine(session, LockType.Shared);
|
||||
IProgress powerDownProgress = session.getConsole().powerDown();
|
||||
@Override
|
||||
public Void apply(ISession arg0) {
|
||||
IProgress powerDownProgress = arg0.getConsole().powerDown();
|
||||
powerDownProgress.waitForCompletion(-1);
|
||||
session.unlockMachine();
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
try {
|
||||
logger.debug("Stopping Jetty server...");
|
||||
server.stop();
|
||||
|
@ -234,13 +246,50 @@ public class IsoToIMachine implements Function<String, IMachine> {
|
|||
return vm;
|
||||
}
|
||||
|
||||
public void ensureMachineHasIDEControllerNamed(String vmName, String controllerIDE) {
|
||||
lockMachineAndApply(manager, Write, checkNotNull(vmName, "vmName"),
|
||||
new AddIDEControllerIfNotExists(checkNotNull(controllerIDE, "controllerIDE")));
|
||||
}
|
||||
|
||||
public static <T> T lockMachineAndApply(VirtualBoxManager manager, final LockType type, final String machineId,
|
||||
final Function<IMachine, T> function) {
|
||||
return lockSessionOnMachineAndApply(manager, type, machineId, new Function<ISession, T>() {
|
||||
|
||||
@Override
|
||||
public T apply(ISession arg0) {
|
||||
return function.apply(arg0.getMachine());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return function.toString();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static <T> T lockSessionOnMachineAndApply(VirtualBoxManager manager, LockType type, String machineId,
|
||||
Function<ISession, T> function) {
|
||||
try {
|
||||
ISession session = manager.getSessionObject();
|
||||
IMachine immutableMachine = manager.getVBox().findMachine(machineId);
|
||||
immutableMachine.lockMachine(session, type);
|
||||
try {
|
||||
return function.apply(session);
|
||||
} finally {
|
||||
session.unlockMachine();
|
||||
}
|
||||
} catch (VBoxException e) {
|
||||
throw new RuntimeException(String.format("error applying %s to %s with %s lock: %s", function, machineId,
|
||||
type, e.getMessage()), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String defaultInstallSequence() {
|
||||
return "<Esc><Esc><Enter> "
|
||||
+ "/install/vmlinuz noapic preseed/url=http://10.0.2.2:8080/src/test/resources/preseed.cfg "
|
||||
+ "debian-installer=en_US auto locale=en_US kbd-chooser/method=us "
|
||||
+ "hostname="
|
||||
+ vmName
|
||||
+ " "
|
||||
+ "debian-installer=en_US auto locale=en_US kbd-chooser/method=us " + "hostname=" + vmName + " "
|
||||
+ "fb=false debconf/frontend=noninteractive "
|
||||
+ "keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false "
|
||||
+ "initrd=/install/initrd.gz -- <Enter>";
|
||||
|
@ -252,8 +301,7 @@ public class IsoToIMachine implements Function<String, IMachine> {
|
|||
for (String line : sequenceSplited) {
|
||||
String converted = stringToKeycode(line);
|
||||
for (String word : converted.split(" ")) {
|
||||
sb.append("vboxmanage controlvm " + vmName
|
||||
+ " keyboardputscancode " + word + "; ");
|
||||
sb.append("vboxmanage controlvm " + vmName + " keyboardputscancode " + word + "; ");
|
||||
if (word.endsWith(KeyboardScancodes.SPECIAL_KEYBOARD_BUTTON_MAP.get("<Enter>"))) {
|
||||
runScriptOnNode(hostId, sb.toString(), runAsRoot(false).wrapInInitScript(false));
|
||||
sb.delete(0, sb.length() - 1);
|
||||
|
@ -272,8 +320,7 @@ public class IsoToIMachine implements Function<String, IMachine> {
|
|||
if (s.startsWith("<")) {
|
||||
String[] specials = s.split("<");
|
||||
for (int i = 1; i < specials.length; i++) {
|
||||
keycodes.append(KeyboardScancodes.SPECIAL_KEYBOARD_BUTTON_MAP
|
||||
.get("<" + specials[i]) + " ");
|
||||
keycodes.append(KeyboardScancodes.SPECIAL_KEYBOARD_BUTTON_MAP.get("<" + specials[i]) + " ");
|
||||
}
|
||||
return keycodes.toString();
|
||||
}
|
||||
|
@ -281,15 +328,13 @@ public class IsoToIMachine implements Function<String, IMachine> {
|
|||
int i = 0;
|
||||
while (i < s.length()) {
|
||||
String digit = s.substring(i, i + 1);
|
||||
String hex = KeyboardScancodes.NORMAL_KEYBOARD_BUTTON_MAP
|
||||
.get(digit);
|
||||
String hex = KeyboardScancodes.NORMAL_KEYBOARD_BUTTON_MAP.get(digit);
|
||||
keycodes.append(hex + " ");
|
||||
if (i != 0 && i % 14 == 0)
|
||||
keycodes.append(" ");
|
||||
i++;
|
||||
}
|
||||
keycodes.append(KeyboardScancodes.SPECIAL_KEYBOARD_BUTTON_MAP
|
||||
.get("<Spacebar>") + " ");
|
||||
keycodes.append(KeyboardScancodes.SPECIAL_KEYBOARD_BUTTON_MAP.get("<Spacebar>") + " ");
|
||||
|
||||
return keycodes.toString();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* 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 static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.createNiceMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import org.virtualbox_4_1.IMachine;
|
||||
import org.virtualbox_4_1.IStorageController;
|
||||
import org.virtualbox_4_1.StorageBus;
|
||||
import org.virtualbox_4_1.VBoxException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
@Test(groups = "unit", testName = "AddIDEControllerIfNotExistsTest")
|
||||
public class AddIDEControllerIfNotExistsTest {
|
||||
|
||||
@Test
|
||||
public void testFine() throws Exception {
|
||||
IMachine vm = createMock(IMachine.class);
|
||||
|
||||
String controllerName = "IDE Controller";
|
||||
|
||||
expect(vm.addStorageController(controllerName, StorageBus.IDE)).andReturn(
|
||||
createNiceMock(IStorageController.class));
|
||||
vm.saveSettings();
|
||||
|
||||
replay(vm);
|
||||
|
||||
new AddIDEControllerIfNotExists(controllerName).apply(vm);
|
||||
|
||||
verify(vm);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptableException() throws Exception {
|
||||
IMachine vm = createMock(IMachine.class);
|
||||
|
||||
String controllerName = "IDE Controller";
|
||||
|
||||
expect(vm.addStorageController(controllerName, StorageBus.IDE)).andThrow(
|
||||
new VBoxException(createNiceMock(Throwable.class),
|
||||
"VirtualBox error: Storage controller named 'IDE Controller' already exists (0x80BB000C)"));
|
||||
|
||||
replay(vm);
|
||||
|
||||
new AddIDEControllerIfNotExists(controllerName).apply(vm);
|
||||
|
||||
verify(vm);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = VBoxException.class)
|
||||
public void testUnacceptableException() throws Exception {
|
||||
IMachine vm = createMock(IMachine.class);
|
||||
|
||||
String controllerName = "IDE Controller";
|
||||
|
||||
expect(vm.addStorageController(controllerName, StorageBus.IDE)).andThrow(
|
||||
new VBoxException(createNiceMock(Throwable.class), "VirtualBox error: General Error"));
|
||||
|
||||
replay(vm);
|
||||
|
||||
new AddIDEControllerIfNotExists(controllerName).apply(vm);
|
||||
|
||||
verify(vm);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue