From f4a53fa0da0b6865de5ab6c5ca78c9f06f832633 Mon Sep 17 00:00:00 2001 From: Mattias Holmqvist Date: Fri, 28 Oct 2011 07:43:34 +0200 Subject: [PATCH] Added LaunchMachineIfNotAlreadyRunning to IsoToIMachine. --- .../jclouds/virtualbox/domain/ErrorCode.java | 46 +++++----- .../virtualbox/functions/IsoToIMachine.java | 64 +++++++------ .../LaunchMachineIfNotAlreadyRunning.java | 91 +++++++++++++++++++ .../LaunchMachineIfNotAlreadyRunningTest.java | 67 ++++++++++++++ 4 files changed, 219 insertions(+), 49 deletions(-) create mode 100644 sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/LaunchMachineIfNotAlreadyRunning.java create mode 100644 sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/LaunchMachineIfNotAlreadyRunningTest.java diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/ErrorCode.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/ErrorCode.java index 395cc53451..74801270d5 100644 --- a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/ErrorCode.java +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/domain/ErrorCode.java @@ -46,27 +46,27 @@ import java.util.Map; */ public enum ErrorCode { - E_OBJECT_NOT_FOUND(2159738881L), - E_INVALID_VM_STATE(2159738882L), - E_VM_ERROR(2159738883L), - E_FILE_ERROR(2159738884L), - E_IPRT_ERROR(2159738885L), - E_PDM_ERROR(2159738886L), - E_INVALID_OBJECT_STATE(2159738887L), - E_HOST_ERROR(2159738888L), - E_NOT_SUPPORTED(2159738889L), - E_XML_ERROR(2159738890L), - E_INVALID_SESSION_STATE(2159738891L), - E_OBJECT_IN_USE(2159738892L), - E_ACCESSDENIED(2147942405L), - E_POINTER(2147500035L), - E_FAIL(2147500037L), - E_NOTIMPL(2147500033L), - E_OUTOFMEMORY(2147942414L), - E_INVALIDARG(2147942487L), - E_UNEXPECTED(2147549183L), - E_UNKNOWN_ERROR_CODE(-1L), - E_ERROR_CODE_UNAVAILABLE(-2L); + VBOX_E_OBJECT_NOT_FOUND(2159738881L), + VBOX_E_INVALID_VM_STATE(2159738882L), + VBOX_E_VM_ERROR(2159738883L), + VBOX_E_FILE_ERROR(2159738884L), + VBOX_E_IPRT_ERROR(2159738885L), + VBOX_E_PDM_ERROR(2159738886L), + VBOX_E_INVALID_OBJECT_STATE(2159738887L), + VBOX_E_HOST_ERROR(2159738888L), + VBOX_E_NOT_SUPPORTED(2159738889L), + VBOX_E_XML_ERROR(2159738890L), + VBOX_E_INVALID_SESSION_STATE(2159738891L), + VBOX_E_OBJECT_IN_USE(2159738892L), + VBOX_E_ACCESSDENIED(2147942405L), + VBOX_E_POINTER(2147500035L), + VBOX_E_FAIL(2147500037L), + VBOX_E_NOTIMPL(2147500033L), + VBOX_E_OUTOFMEMORY(2147942414L), + VBOX_E_INVALIDARG(2147942487L), + VBOX_E_UNEXPECTED(2147549183L), + VBOX_E_UNKNOWN_ERROR_CODE(-1L), + VBOX_E_ERROR_CODE_UNAVAILABLE(-2L); private long code; @@ -97,9 +97,9 @@ public enum ErrorCode { if (errorCode != null) { return errorCode; } - return E_UNKNOWN_ERROR_CODE; + return VBOX_E_UNKNOWN_ERROR_CODE; } - return E_ERROR_CODE_UNAVAILABLE; + return VBOX_E_ERROR_CODE_UNAVAILABLE; } private static long unsignedIntToLong(int faultCode) { 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 caddb16998..9761738a15 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 @@ -19,23 +19,8 @@ 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; -import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE; -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.DeviceType.HardDisk; -import static org.virtualbox_4_1.LockType.Shared; -import static org.virtualbox_4_1.LockType.Write; - -import java.io.File; - -import javax.annotation.Resource; -import javax.inject.Named; - +import com.google.common.base.Function; +import com.google.inject.Inject; import org.eclipse.jetty.server.Server; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.domain.ExecResponse; @@ -46,12 +31,25 @@ import org.jclouds.javax.annotation.Nullable; import org.jclouds.logging.Logger; import org.jclouds.ssh.SshException; import org.jclouds.virtualbox.config.VirtualBoxConstants; +import org.jclouds.virtualbox.domain.ExecutionType; import org.jclouds.virtualbox.functions.admin.StartJettyIfNotAlreadyRunning; import org.jclouds.virtualbox.settings.KeyboardScancodes; import org.virtualbox_4_1.*; -import com.google.common.base.Function; -import com.google.inject.Inject; +import javax.annotation.Resource; +import javax.inject.Named; +import java.io.File; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot; +import static org.jclouds.compute.options.RunScriptOptions.Builder.wrapInInitScript; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE; +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.DeviceType.HardDisk; +import static org.virtualbox_4_1.LockType.Shared; +import static org.virtualbox_4_1.LockType.Write; public class IsoToIMachine implements Function { @@ -136,13 +134,8 @@ public class IsoToIMachine implements Function { // Guest additions ensureGuestAdditionsMediumIsAttached(vmName, guestAdditionsDvdMedium); - IProgress prog = vm.launchVMProcess(manager.getSessionObject(), "gui", ""); - prog.waitForCompletion(-1); - try { - Thread.sleep(5000); - } catch (InterruptedException e) { - propagate(e); - } + // Launch machine and wait for it to come online + ensureMachineIsLaunched(vmName); String installKeySequence = System.getProperty(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE, defaultInstallSequence()); sendKeyboardSequence(installKeySequence); @@ -180,6 +173,10 @@ public class IsoToIMachine implements Function { return vm; } + private void ensureMachineIsLaunched(String vmName) { + applyForMachine(manager, vmName, new LaunchMachineIfNotAlreadyRunning(manager, ExecutionType.GUI, "")); + } + private void ensureGuestAdditionsMediumIsAttached(String vmName, final IMedium guestAdditionsDvdMedium) { lockMachineAndApply(manager, Write, vmName, new AttachMediumToMachineIfNotAlreadyAttached(controllerIDE, guestAdditionsDvdMedium, 1, 1, DeviceType.DVD)); @@ -219,6 +216,21 @@ public class IsoToIMachine implements Function { new AddIDEControllerIfNotExists(checkNotNull(controllerIDE, "controllerIDE"))); } + private T applyForMachine(VirtualBoxManager manager, final String machineId, final Function function) { + final IMachine immutableMachine = manager.getVBox().findMachine(machineId); + return new Function() { + @Override + public T apply(IMachine machine) { + return function.apply(machine); + } + + @Override + public String toString() { + return function.toString(); + } + }.apply(immutableMachine); + } + public static T lockMachineAndApply(VirtualBoxManager manager, final LockType type, final String machineId, final Function function) { return lockSessionOnMachineAndApply(manager, type, machineId, new Function() { diff --git a/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/LaunchMachineIfNotAlreadyRunning.java b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/LaunchMachineIfNotAlreadyRunning.java new file mode 100644 index 0000000000..a118c77658 --- /dev/null +++ b/sandbox-apis/virtualbox/src/main/java/org/jclouds/virtualbox/functions/LaunchMachineIfNotAlreadyRunning.java @@ -0,0 +1,91 @@ +/* + * 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.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; +import org.jclouds.virtualbox.domain.ErrorCode; +import org.jclouds.virtualbox.domain.ExecutionType; +import org.virtualbox_4_1.*; +import org.virtualbox_4_1.jaxws.RuntimeFaultMsg; + +import javax.annotation.Nullable; +import javax.annotation.Resource; +import javax.inject.Named; +import javax.lang.model.type.ExecutableType; + +import static com.google.common.base.Throwables.propagate; +import static javax.xml.bind.DatatypeConverter.parseUnsignedInt; + +/** + * Starts a machine using launchMachine() with the provided type and environment. + *

+ * Note that launchMachine() may throw VBoxException with the following error codes: + *

+ * VBOX_E_UNEXPECTED: Virtual machine not registered. + * VBOX_E_INVALIDARG: Invalid session type type. + * VBOX_E_OBJECT_NOT_FOUND: No machine matching machineId found. + * VBOX_E_INVALID_OBJECT_STATE: Session already open or being opened. + * VBOX_E_IPRT_ERROR: Launching process for machine failed. + * VBOX_E_VM_ERROR: Failed to assign machine to session. + * + * @author Mattias Holmqvist + * + * @see ErrorCode + */ +public class LaunchMachineIfNotAlreadyRunning implements Function { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final VirtualBoxManager manager; + private final ExecutionType type; + private final String environment; + + public LaunchMachineIfNotAlreadyRunning(VirtualBoxManager manager, ExecutionType type, String environment) { + this.manager = manager; + this.type = type; + this.environment = environment; + } + + @Override + public Void apply(@Nullable IMachine machine) { + try { + final IProgress progress = machine.launchVMProcess(manager.getSessionObject(), type.stringValue(), environment); + progress.waitForCompletion(-1); + Thread.sleep(5000); + } catch (InterruptedException e) { + propagate(e); + } catch (VBoxException e) { + ErrorCode errorCode = ErrorCode.valueOf(e); + switch (errorCode) { + case VBOX_E_INVALID_OBJECT_STATE: + logger.warn(e, "Could not start machine. Got error code %s from launchMachine(). " + + "The machine might already be running.", errorCode); + break; + default: + propagate(e); + } + } + return null; + } +} diff --git a/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/LaunchMachineIfNotAlreadyRunningTest.java b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/LaunchMachineIfNotAlreadyRunningTest.java new file mode 100644 index 0000000000..c512905735 --- /dev/null +++ b/sandbox-apis/virtualbox/src/test/java/org/jclouds/virtualbox/functions/LaunchMachineIfNotAlreadyRunningTest.java @@ -0,0 +1,67 @@ +/* + * 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.jclouds.virtualbox.domain.ExecutionType; +import org.testng.annotations.Test; +import org.virtualbox_4_1.IMachine; +import org.virtualbox_4_1.IProgress; +import org.virtualbox_4_1.ISession; +import org.virtualbox_4_1.VirtualBoxManager; + +import static org.easymock.classextension.EasyMock.verify; +import static org.easymock.classextension.EasyMock.replay; +import static org.easymock.classextension.EasyMock.createMock; +import static org.easymock.classextension.EasyMock.expect; + +@Test(groups = "unit", testName = "LaunchMachineIfNotAlreadyRunningTest") +public class LaunchMachineIfNotAlreadyRunningTest { + + @Test + public void testDoNotLaunchIfAlreadyRunning() throws Exception { + + } + +// VirtualBox error: The given session is busy (0x80BB0007) +// VirtualBox error: The machine 'jclouds-image-virtualbox-iso-to-machine-test' is not registered (0x8000FFFF) + + + @Test + public void testLaunchIfNotStarted() throws Exception { + + final String type = "gui"; + final String environment = ""; + ISession session = createMock(ISession.class); + VirtualBoxManager manager = createMock(VirtualBoxManager.class); + IMachine machine = createMock(IMachine.class); + IProgress progress = createMock(IProgress.class); + + expect(manager.getSessionObject()).andReturn(session); + expect(machine.launchVMProcess(session, type, environment)).andReturn(progress); + progress.waitForCompletion(-1); + + replay(manager, machine, session, progress); + + new LaunchMachineIfNotAlreadyRunning(manager, ExecutionType.GUI, "").apply(machine); + + verify(manager, machine, session, progress); + + } +}