diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java index 5ae08a2338..eb0a889c3a 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java @@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Iterables.filter; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_NAME_SEPARATOR; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX; import java.util.Map; @@ -63,7 +64,7 @@ import com.google.inject.Singleton; * Defines the connection between the {@link org.virtualbox_4_1.VirtualBoxManager} implementation * and the jclouds {@link org.jclouds.compute.ComputeService} * - * @author Mattias Holmqvist, Andrea Turli + * @author Mattias Holmqvist, Andrea Turli, David Alves */ @Singleton public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter { @@ -91,6 +92,10 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter createNodeWithGroupEncodedIntoName(String tag, String name, Template template) { try { + checkState(!tag.contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "tag names cannot contain \"" + + VIRTUALBOX_NODE_NAME_SEPARATOR + "\""); + checkState(!name.contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "node names cannot contain \"" + + VIRTUALBOX_NODE_NAME_SEPARATOR + "\""); Master master = mastersLoader.get(template.getImage()); checkState(master != null, "could not find a master for image: "+template.getClass()); NodeSpec nodeSpec = NodeSpec.builder().master(master).name(name).tag(tag).template(template).build(); diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java index 7ca72d7108..fcaac83da1 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java @@ -158,7 +158,7 @@ public class VirtualBoxComputeServiceContextModule extends bind(new TypeLiteral>() { }).to(IMachineToSshClient.class); - bind(ExecutionType.class).toInstance(ExecutionType.GUI); + bind(ExecutionType.class).toInstance(ExecutionType.HEADLESS); bind(LockType.class).toInstance(LockType.Write); } diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxConstants.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxConstants.java index bfa84608f2..909297682b 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxConstants.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxConstants.java @@ -24,14 +24,16 @@ import java.io.File; /** * Configuration properties used for interacting with VirtualBox instances. * - * @author Mattias Holmqvist, Andrea Turli + * @author Mattias Holmqvist, Andrea Turli, David Alves * */ public interface VirtualBoxConstants { - public static final String VIRTUALBOX_IMAGE_PREFIX = "jclouds-image-"; + public static final String VIRTUALBOX_NODE_NAME_SEPARATOR = "-0x0-"; + + public static final String VIRTUALBOX_IMAGE_PREFIX = "jclouds-image" + VIRTUALBOX_NODE_NAME_SEPARATOR; - public static final String VIRTUALBOX_NODE_PREFIX = "jclouds-node-"; + public static final String VIRTUALBOX_NODE_PREFIX = "jclouds-node" + VIRTUALBOX_NODE_NAME_SEPARATOR; public static final String VIRTUALBOX_PRECONFIGURATION_URL = "jclouds.virtualbox.preconfigurationurl"; diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java index 336225926f..bf75aa686d 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java @@ -29,6 +29,7 @@ import javax.annotation.Resource; import javax.inject.Named; import javax.inject.Singleton; +import org.jclouds.Constants; import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.options.RunScriptOptions; @@ -39,16 +40,16 @@ import org.jclouds.virtualbox.Preconfiguration; import org.jclouds.virtualbox.domain.IsoSpec; import org.jclouds.virtualbox.domain.MasterSpec; import org.jclouds.virtualbox.domain.VmSpec; -import org.jclouds.virtualbox.predicates.GuestAdditionsInstaller; +import org.jclouds.virtualbox.statements.InstallGuestAdditions; import org.jclouds.virtualbox.util.MachineController; import org.jclouds.virtualbox.util.MachineUtils; import org.virtualbox_4_1.IMachine; -import org.virtualbox_4_1.LockType; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Splitter; import com.google.common.cache.LoadingCache; +import com.google.common.collect.Iterables; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.Inject; @@ -61,32 +62,32 @@ public class CreateAndInstallVm implements Function { protected Logger logger = Logger.NULL; private final CreateAndRegisterMachineFromIsoIfNotAlreadyExists createAndRegisterMachineFromIsoIfNotAlreadyExists; - private final GuestAdditionsInstaller guestAdditionsInstaller; private final Predicate sshResponds; private LoadingCache preConfiguration; private final Function sshClientForIMachine; private final MachineUtils machineUtils; private final IMachineToNodeMetadata imachineToNodeMetadata; private final MachineController machineController; + private final String version; @Inject public CreateAndInstallVm( CreateAndRegisterMachineFromIsoIfNotAlreadyExists CreateAndRegisterMachineFromIsoIfNotAlreadyExists, - GuestAdditionsInstaller guestAdditionsInstaller, IMachineToNodeMetadata imachineToNodeMetadata, Predicate sshResponds, Function sshClientForIMachine, MachineUtils machineUtils, - @Preconfiguration LoadingCache preConfiguration, MachineController machineController) { + @Preconfiguration LoadingCache preConfiguration, + MachineController machineController, @Named(Constants.PROPERTY_BUILD_VERSION) String version) { this.createAndRegisterMachineFromIsoIfNotAlreadyExists = CreateAndRegisterMachineFromIsoIfNotAlreadyExists; this.sshResponds = sshResponds; this.sshClientForIMachine = sshClientForIMachine; this.machineUtils = machineUtils; this.preConfiguration = preConfiguration; - this.guestAdditionsInstaller = guestAdditionsInstaller; this.imachineToNodeMetadata = imachineToNodeMetadata; this.machineController = machineController; + this.version = Iterables.get(Splitter.on('r').split(version), 0); } @Override @@ -117,26 +118,28 @@ public class CreateAndInstallVm implements Function { "timed out waiting for guest %s to be accessible via ssh", vmName); - logger.debug(">> awaiting installation of guest additions on vm: %s", vmName); - checkState(guestAdditionsInstaller.apply(vm)); + logger.debug(">> awaiting installation of guest additions on vm: %s", vmName); - logger.debug(">> awaiting post-installation actions on vm: %s", vmName); + ListenableFuture execFuture = machineUtils.runScriptOnNode(imachineToNodeMetadata.apply(vm), + new InstallGuestAdditions(vmSpec, version), RunScriptOptions.NONE); + ExecResponse execResponse = Futures.getUnchecked(execFuture); - NodeMetadata vmMetadata = imachineToNodeMetadata.apply(vm); + checkState(execResponse.getExitStatus() == 0); - ListenableFuture execFuture = - machineUtils.runScriptOnNode(vmMetadata, call("cleanupUdevIfNeeded"), RunScriptOptions.NONE); + logger.debug(">> awaiting post-installation actions on vm: %s", vmName); - ExecResponse execResponse = Futures.getUnchecked(execFuture); - checkState(execResponse.getExitStatus() == 0); + NodeMetadata vmMetadata = imachineToNodeMetadata.apply(vm); - logger.debug( - "<< installation of image complete. Powering down node(%s)", - vmName); + execFuture = machineUtils.runScriptOnNode(vmMetadata, call("cleanupUdevIfNeeded"), RunScriptOptions.NONE); - machineController.ensureMachineHasPowerDown(vmName); - return vm; - } + execResponse = Futures.getUnchecked(execFuture); + checkState(execResponse.getExitStatus() == 0); + + logger.debug("<< installation of image complete. Powering down node(%s)", vmName); + + machineController.ensureMachineHasPowerDown(vmName); + return vm; + } private void configureOsInstallationWithKeyboardSequence(String vmName, String installationKeySequence) { @@ -144,8 +147,7 @@ public class CreateAndInstallVm implements Function { .split(installationKeySequence), new StringToKeyCode()); for (List scancodes : scancodelist) { - machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, - new SendScancodes(scancodes)); + machineUtils.sharedLockMachineAndApplyToSession(vmName,new SendScancodes(scancodes)); } } diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java index e95d405543..dae1df8a04 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java @@ -22,6 +22,7 @@ package org.jclouds.virtualbox.functions; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static org.jclouds.virtualbox.config.VirtualBoxComputeServiceContextModule.machineToNodeState; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.*; import javax.annotation.Resource; import javax.inject.Named; @@ -54,8 +55,18 @@ public class IMachineToNodeMetadata implements Function @Override public NodeMetadata apply(@Nullable IMachine vm) { + String group = ""; + String name = ""; + String[] encodedInVmName = vm.getName().split(VIRTUALBOX_NODE_NAME_SEPARATOR); + if (vm.getName().startsWith(VIRTUALBOX_NODE_PREFIX)){ + group = encodedInVmName[2]; + name = encodedInVmName[3]; + } else { + name = encodedInVmName[1]; + } + NodeMetadataBuilder nodeMetadataBuilder = new NodeMetadataBuilder(); - nodeMetadataBuilder.name(vm.getName()).ids(vm.getName()); + nodeMetadataBuilder.name(name).ids(vm.getName()).group(group); // TODO Set up location properly LocationBuilder locationBuilder = new LocationBuilder(); @@ -63,7 +74,6 @@ public class IMachineToNodeMetadata implements Function locationBuilder.id(""); locationBuilder.scope(LocationScope.HOST); nodeMetadataBuilder.location(locationBuilder.build()); - nodeMetadataBuilder.hostname(vm.getName()); MachineState vmState = vm.getState(); @@ -74,8 +84,6 @@ public class IMachineToNodeMetadata implements Function logger.debug("Setting virtualbox node to: " + nodeState + " from machine state: " + vmState); - // hardcoded set-up that works only for nat+host-only - // nat adapter INetworkAdapter natAdapter = vm.getNetworkAdapter(0l); checkNotNull(natAdapter, "slot 0 networkadapter"); @@ -83,23 +91,30 @@ public class IMachineToNodeMetadata implements Function "expecting slot 0 to be a NAT attachment type (was: " + natAdapter.getAttachmentType() + ")"); int ipTermination = 0; + int inPort = 0; + String hostAddress = ""; nodeMetadataBuilder.publicAddresses(ImmutableSet.of(natAdapter.getNatDriver().getHostIP())); for (String nameProtocolnumberAddressInboudportGuestTargetport : natAdapter.getNatDriver().getRedirects()) { Iterable stuff = Splitter.on(',').split(nameProtocolnumberAddressInboudportGuestTargetport); String protocolNumber = Iterables.get(stuff, 1); + hostAddress = Iterables.get(stuff, 2); String inboundPort = Iterables.get(stuff, 3); String targetPort = Iterables.get(stuff, 5); if ("1".equals(protocolNumber) && "22".equals(targetPort)) { - int inPort = Integer.parseInt(inboundPort); + inPort = Integer.parseInt(inboundPort); ipTermination = inPort % NodeCreator.NODE_PORT_INIT + 2; -// nodeMetadataBuilder.publicAddresses(ImmutableSet.of(hostAddress)).loginPort(inPort); } } - - nodeMetadataBuilder.privateAddresses(ImmutableSet.of((NodeCreator.VMS_NETWORK + ipTermination) + "")); - nodeMetadataBuilder.publicAddresses(ImmutableSet.of((NodeCreator.VMS_NETWORK + ipTermination) + "")); - + + // only masters use 2222 port + if (inPort == MastersLoadingCache.MASTER_PORT) { + nodeMetadataBuilder.publicAddresses(ImmutableSet.of(hostAddress)).loginPort(inPort); + } else { + nodeMetadataBuilder.privateAddresses(ImmutableSet.of((NodeCreator.VMS_NETWORK + ipTermination) + "")); + nodeMetadataBuilder.publicAddresses(ImmutableSet.of((NodeCreator.VMS_NETWORK + ipTermination) + "")); + } + LoginCredentials loginCredentials = new LoginCredentials("toor", "password", null, true); nodeMetadataBuilder.credentials(loginCredentials); diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java index 85b81bf3ac..e87a0a6c16 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java @@ -24,6 +24,7 @@ import static com.google.common.base.Preconditions.checkState; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAULT_DIR; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_NAME_SEPARATOR; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_WORKINGDIR; import static org.jclouds.virtualbox.util.MachineUtils.machineNotFoundException; @@ -132,6 +133,14 @@ public class MastersLoadingCache extends AbstractLoadingCache { return masters.get(key.getId()); } + // the yaml image + YamlImage yamlImage = imageMapping.get(key.getId()); + + checkNotNull(yamlImage, "could not find yaml image for image: " + key); + + checkState(!yamlImage.id.contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "master image names cannot contain \"" + + VIRTUALBOX_NODE_NAME_SEPARATOR + "\""); + String guestAdditionsFileName = String.format("VBoxGuestAdditions_%s.iso", version); String guestAdditionsIso = String.format("%s/%s", isosDir, guestAdditionsFileName); String guestAdditionsUri = "http://download.virtualbox.org/virtualbox/" + version + "/" + guestAdditionsFileName; @@ -140,11 +149,6 @@ public class MastersLoadingCache extends AbstractLoadingCache { } checkState(new File(guestAdditionsIso).exists(), "guest additions iso does not exist at: " + guestAdditionsIso); - // the yaml image - YamlImage yamlImage = imageMapping.get(key.getId()); - - checkNotNull(yamlImage, "could not find yaml image for image: " + key); - // check if the iso is here, download if not String localIsoUrl = getFilePathOrDownload(yamlImage.iso); @@ -156,13 +160,13 @@ public class MastersLoadingCache extends AbstractLoadingCache { .build(); StorageController ideController = StorageController.builder().name("IDE Controller").bus(StorageBus.IDE) - .attachISO(0, 0, localIsoUrl).attachHardDisk(hardDisk).attachISO(1, 1, guestAdditionsIso).build(); + .attachISO(0, 0, localIsoUrl).attachHardDisk(hardDisk).attachISO(1, 0, guestAdditionsIso).build(); VmSpec vmSpecification = VmSpec.builder().id(yamlImage.id).name(vmName).memoryMB(512).osTypeId("") .controller(ideController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build(); NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT) - .tcpRedirectRule("127.0.0.1", MASTER_PORT, "", 22).build(); + .tcpRedirectRule("127.0.0.1", MASTER_PORT , "", 22).build(); NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter) .slot(0L).build(); diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MutableMachine.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MutableMachine.java deleted file mode 100644 index 94555d7bb8..0000000000 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MutableMachine.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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 javax.annotation.Resource; -import javax.inject.Named; -import javax.inject.Singleton; - -import org.jclouds.compute.reference.ComputeServiceConstants; -import org.jclouds.logging.Logger; -import org.virtualbox_4_1.IMachine; -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 com.google.common.base.Function; -import com.google.common.base.Supplier; -import com.google.inject.Inject; - -@Singleton -public class MutableMachine implements Function { - - @Resource - @Named(ComputeServiceConstants.COMPUTE_LOGGER) - protected Logger logger = Logger.NULL; - - private final Supplier manager; - private final LockType lockType; - - - @Inject - public MutableMachine(Supplier manager, - LockType lockType) { - this.manager = manager; - this.lockType = lockType; - } - - @Override - public ISession apply(String machineId) { - return lockSessionOnMachineAndReturn(manager.get(), lockType, machineId); - } - - /** - * Locks the machine and executes the given function using the current session. - * Since the machine is locked it is possible to perform some modifications to the IMachine. - *

- * Unlocks the machine before returning. - * - * @param manager the VirtualBoxManager - * @param type the kind of lock to use when initially locking the machine. - * @param machineId the id of the machine - * @return the ISession bounded to the machine locked. - */ - public static ISession lockSessionOnMachineAndReturn(VirtualBoxManager manager, LockType type, String machineId) { - try { - ISession session = manager.getSessionObject(); - IMachine immutableMachine = manager.getVBox().findMachine(machineId); - immutableMachine.lockMachine(session, type); - return session; - } catch (VBoxException e) { - throw new RuntimeException(String.format("error locking %s with %s lock: %s", machineId, - type, e.getMessage()), e); - } - } - - -} diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java index 6414f9e07d..bef7f792c7 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java @@ -21,6 +21,7 @@ package org.jclouds.virtualbox.functions; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_NAME_SEPARATOR; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX; import java.util.concurrent.atomic.AtomicInteger; @@ -45,6 +46,7 @@ import org.jclouds.virtualbox.domain.NodeSpec; import org.jclouds.virtualbox.domain.VmSpec; import org.jclouds.virtualbox.statements.DeleteGShadowLock; import org.jclouds.virtualbox.statements.SetIpAddress; +import org.jclouds.virtualbox.util.MachineController; import org.jclouds.virtualbox.util.MachineUtils; import org.virtualbox_4_1.CleanupMode; import org.virtualbox_4_1.IMachine; @@ -64,7 +66,7 @@ import com.google.common.collect.Iterables; * Creates nodes, by cloning a master vm and based on the provided {@link NodeSpec}. Must be * synchronized mainly because of snapshot creation (must be synchronized on a per-master-basis). * - * @author dralves + * @author David Alves * */ @Singleton @@ -82,32 +84,22 @@ public class NodeCreator implements Function manager; private final Function cloner; private final AtomicInteger nodePorts; private final AtomicInteger nodeIps; - private MachineUtils machineUtils; - private Function imachineToNodeMetadata; - - private final RunScriptOnNode.Factory scriptRunnerFactory; - private final Supplier hostSupplier; + private final MachineUtils machineUtils; + private final MachineController machineController; @Inject public NodeCreator(Supplier manager, Function cloner, - MachineUtils machineUtils, Function imachineToNodeMetadata, - RunScriptOnNode.Factory scriptRunnerFactory, Supplier hostSupplier) { + MachineUtils machineUtils, RunScriptOnNode.Factory scriptRunnerFactory, MachineController machineController) { this.manager = manager; this.cloner = cloner; this.nodePorts = new AtomicInteger(NODE_PORT_INIT); this.nodeIps = new AtomicInteger(2); this.machineUtils = machineUtils; - this.imachineToNodeMetadata = imachineToNodeMetadata; - this.scriptRunnerFactory = scriptRunnerFactory; - this.hostSupplier = hostSupplier; - + this.machineController = machineController; } @Override @@ -131,8 +123,8 @@ public class NodeCreator implements Function { - - @Resource - @Named(ComputeServiceConstants.COMPUTE_LOGGER) - protected Logger logger = Logger.NULL; - - private final IMachineToNodeMetadata imachineToNodeMetadata; - private final MachineUtils machineUtils; - private final Supplier manager; - - @Inject - public GuestAdditionsInstaller(Supplier manager, MachineUtils machineUtils, - IMachineToNodeMetadata imachineToNodeMetadata) { - this.machineUtils = machineUtils; - this.imachineToNodeMetadata = imachineToNodeMetadata; - this.manager = manager; - } - - @Override - public boolean apply(IMachine machine) { - String vboxVersion = Iterables.get(Splitter.on('r').split(manager.get().getVBox().getVersion()), 0); - ListenableFuture execFuture = machineUtils.runScriptOnNode(imachineToNodeMetadata.apply(machine), - new InstallGuestAdditions(vboxVersion), RunScriptOptions.NONE); - ExecResponse execResponse = Futures.getUnchecked(execFuture); - return execResponse == null ? false : execResponse.getExitStatus() == 0; - } - -} \ No newline at end of file diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java index 6d6e5a7122..2f85e40625 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/InstallGuestAdditions.java @@ -25,34 +25,82 @@ import static org.jclouds.scriptbuilder.domain.Statements.exec; import static org.jclouds.scriptbuilder.domain.Statements.saveHttpResponseTo; import java.net.URI; +import java.util.List; +import javax.annotation.Resource; +import javax.inject.Named; + +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; import org.jclouds.scriptbuilder.domain.OsFamily; +import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.StatementList; +import org.jclouds.virtualbox.domain.IsoImage; +import org.jclouds.virtualbox.domain.StorageController; +import org.jclouds.virtualbox.domain.VmSpec; +import org.testng.collections.Lists; -public class InstallGuestAdditions extends StatementList { +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; - public InstallGuestAdditions(String vboxVersion) { - this(vboxVersion, "/mnt", "VBoxGuestAdditions_" + vboxVersion + ".iso"); +/** + * Mounts the DVD with guest additions that was downloaded and attached as removeable storage. If no + * guest additions is attached to the vmspec then it is downloaded. + * + * @author David Alves + * + */ +public class InstallGuestAdditions implements Statement { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + private final StatementList statements; + + public InstallGuestAdditions(VmSpec vmSpecification, String vboxVersion) { + this.statements = new StatementList(getStatements(vmSpecification, vboxVersion)); } - public InstallGuestAdditions(String vboxVersion, String mountPoint, String vboxGuestAdditionsIso) { - this(URI.create("http://download.virtualbox.org/virtualbox/" + vboxVersion + "/" + vboxGuestAdditionsIso), - mountPoint, vboxGuestAdditionsIso); - } - - public InstallGuestAdditions(URI download, String mountPoint, String vboxGuestAdditionsIso) { - super(call("setupPublicCurl"), // - saveHttpResponseTo(download, "{tmp}{fs}", vboxGuestAdditionsIso),// - exec(String.format("mount -o loop {tmp}{fs}%s %s", vboxGuestAdditionsIso, mountPoint)), - call("installModuleAssistantIfNeeded"), // - exec(String.format("%s%s", mountPoint, "/VBoxLinuxAdditions.run")), // - exec(String.format("umount %s", mountPoint))); + private List getStatements(VmSpec vmSpecification, String vboxVersion) { + List statements = Lists.newArrayList(); + statements.add(call("installModuleAssistantIfNeeded")); + String mountPoint = "/mnt"; + if (Iterables.tryFind(vmSpecification.getControllers(), new Predicate() { + @Override + public boolean apply(StorageController input) { + if (!input.getIsoImages().isEmpty()) { + for (IsoImage iso : input.getIsoImages()) { + if (iso.getSourcePath().contains("VBoxGuestAdditions_")) { + return true; + } + } + } + return false; + } + }).isPresent()) { + statements.add(exec("mount -t iso9660 /dev/sr1 " + mountPoint)); + } else { + String vboxGuestAdditionsIso = "VBoxGuestAdditions_" + vboxVersion + ".iso"; + URI download = URI.create("http://download.virtualbox.org/virtualbox/" + vboxVersion + "/" + + vboxGuestAdditionsIso); + statements.add(call("setupPublicCurl")); + statements.add(saveHttpResponseTo(download, "{tmp}{fs}", vboxGuestAdditionsIso));// + statements.add(exec(String.format("mount -o loop {tmp}{fs}%s %s", vboxGuestAdditionsIso, mountPoint))); + } + statements.add(exec(String.format("%s%s", mountPoint, "/VBoxLinuxAdditions.run"))); // + statements.add(exec(String.format("umount %s", mountPoint))); + return statements; } @Override public String render(OsFamily family) { if (checkNotNull(family, "family") == OsFamily.WINDOWS) throw new UnsupportedOperationException("windows not yet implemented"); - return super.render(family); + return statements.render(family); + } + + @Override + public Iterable functionDependencies(OsFamily family) { + return statements.functionDependencies(family); } } diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineController.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineController.java index 16b58654d3..548534d7b0 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineController.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineController.java @@ -28,7 +28,6 @@ import org.jclouds.virtualbox.domain.ExecutionType; import org.jclouds.virtualbox.functions.LaunchMachineIfNotAlreadyRunning; import org.virtualbox_4_1.IProgress; import org.virtualbox_4_1.ISession; -import org.virtualbox_4_1.LockType; import org.virtualbox_4_1.VirtualBoxManager; import org.virtualbox_4_1.jaxws.MachineState; @@ -68,7 +67,7 @@ public class MachineController { public void ensureMachineHasPowerDown(String vmName) { while (!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.POWERED_OFF)) { try { - machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, new Function() { + machineUtils.sharedLockMachineAndApplyToSession(vmName, new Function() { @Override public Void apply(ISession session) { IProgress powerDownProgress = session.getConsole().powerDown(); diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineUtils.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineUtils.java index c8616c6b86..296f175b71 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineUtils.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineUtils.java @@ -18,12 +18,6 @@ */ package org.jclouds.virtualbox.util; -import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot; -import static org.jclouds.scriptbuilder.domain.Statements.call; -import static org.jclouds.scriptbuilder.domain.Statements.findPid; -import static org.jclouds.scriptbuilder.domain.Statements.kill; -import static org.jclouds.scriptbuilder.domain.Statements.newStatementList; - import javax.annotation.Resource; import javax.inject.Named; import javax.inject.Singleton; @@ -37,11 +31,9 @@ import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.util.Throwables2; -import org.jclouds.virtualbox.functions.MutableMachine; import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.ISession; import org.virtualbox_4_1.LockType; -import org.virtualbox_4_1.SessionState; import org.virtualbox_4_1.VBoxException; import org.virtualbox_4_1.VirtualBoxManager; @@ -53,7 +45,7 @@ import com.google.inject.Inject; /** * Utilities for executing functions on a VirtualBox machine. * - * @author Adrian Cole, Mattias Holmqvist, Andrea Turli + * @author Adrian Cole, Mattias Holmqvist, Andrea Turli, David Alves */ @Singleton @@ -65,15 +57,12 @@ public class MachineUtils { private final Supplier manager; private final Factory scriptRunner; - private final Supplier host; @Inject - public MachineUtils(Supplier manager, RunScriptOnNode.Factory scriptRunner, - Supplier host) { + public MachineUtils(Supplier manager, RunScriptOnNode.Factory scriptRunner) { super(); this.manager = manager; this.scriptRunner = scriptRunner; - this.host = host; } public ListenableFuture runScriptOnNode(NodeMetadata metadata, Statement statement, @@ -109,12 +98,78 @@ public class MachineUtils { }); } + /** + * Locks the machine and executes the given function using the machine matching the given id. The + * machine is write locked and modifications to the session that reflect on the machine can be + * done safely. + *

+ * Unlocks the machine before returning. + * + * @param machineId + * the id of the machine + * @param function + * the function to execute + * @return the result from applying the function to the machine. + */ + public T writeLockMachineAndApplyToSession(final String machineId, final Function function) { + return lockSessionOnMachineAndApply(machineId, LockType.Write, function); + } + + /** + * Locks the machine and executes the given function using the machine matching the given id. The + * machine is read locked, which means that settings can be read safely (but not changed) by + * function. + *

+ * Unlocks the machine before returning. + * + * @param machineId + * the id of the machine + * @param function + * the function to execute + * @return the result from applying the function to the machine. + */ + public T sharedLockMachineAndApply(final String machineId, final Function function) { + return lockSessionOnMachineAndApply(machineId, LockType.Shared, new Function() { + + @Override + public T apply(ISession session) { + return function.apply(session.getMachine()); + } + + @Override + public String toString() { + return function.toString(); + } + + }); + } + + /** + * Locks the machine and executes the given function to the session using the machine matching + * the given id. The machine is read locked, which means that settings can be read safely (but + * not changed) by function. + *

+ * Unlocks the machine before returning. + * + * @param machineId + * the id of the machine + * @param function + * the function to execute + * @return the result from applying the function to the machine. + */ + public T sharedLockMachineAndApplyToSession(final String machineId, final Function function) { + return lockSessionOnMachineAndApply(machineId, LockType.Shared, function); + } + /** * Locks the machine and executes the given function using the current session. Since the machine * is locked it is possible to perform some modifications to the IMachine. *

* Unlocks the machine before returning. * + * Tries to obtain a lock 5 times before giving up waiting 1 sec between tries. When no machine + * is found null is returned. + * * @param type * the kind of lock to use when initially locking the machine. * @param machineId @@ -123,79 +178,47 @@ public class MachineUtils { * the function to execute * @return the result from applying the function to the session. */ - public T lockSessionOnMachineAndApply(String machineId, LockType type, Function function) { - try { - ISession session = lockSessionOnMachine(type, machineId); + private T lockSessionOnMachineAndApply(String machineId, LockType type, Function function) { + int retries = 5; + int count = 0; + ISession session; + long time = System.currentTimeMillis(); + while (true) { try { - return function.apply(session); - } finally { - session.unlockMachine(); + IMachine immutableMachine = manager.get().getVBox().findMachine(machineId); + session = manager.get().getSessionObject(); + immutableMachine.lockMachine(session, type); + break; + } catch (VBoxException e) { + VBoxException vbex = Throwables2.getFirstThrowableOfType(e, VBoxException.class); + if (vbex != null && machineNotFoundException(vbex)) { + return null; + } + count++; + logger.warn(e, "Could not lock machine (try %d of %d). Error: %s", count, retries, e.getMessage()); + if (count == retries) { + throw new RuntimeException(String.format("error locking %s with %s lock: %s", machineId, type, + e.getMessage()), e); + } + try { + Thread.sleep(1000L); + } catch (InterruptedException e1) { + } } + } + try { + return function.apply(session); } catch (VBoxException e) { throw new RuntimeException(String.format("error applying %s to %s with %s lock: %s", function, machineId, type, e.getMessage()), e); + } finally { + session.unlockMachine(); } } - - private ISession lockSessionOnMachine(LockType type, String machineId) { - return new MutableMachine(manager, type).apply(machineId); - } - - private void unlockMachine(final String machineId) { - IMachine immutableMachine = manager.get().getVBox().findMachine(machineId); - if (immutableMachine.getSessionState().equals(SessionState.Locked)) { - Statement kill = newStatementList(call("default"), findPid(immutableMachine.getSessionPid().toString()), - kill()); - scriptRunner.create(host.get(), kill, runAsRoot(false).wrapInInitScript(false)).init().call(); - } - } - - /** - * Unlocks the machine and executes the given function using the machine matching the given id. - * Since the machine is unlocked it is possible to delete the IMachine. - *

- *

- *

Note!

Currently, this can only unlock the machine, if the lock was created in the - * current session. - * - * @param machineId - * the id of the machine - * @param function - * the function to execute - * @return the result from applying the function to the machine. - */ - public T unlockMachineAndApply(final String machineId, final Function function) { - - try { - unlockMachine(machineId); - IMachine immutableMachine = manager.get().getVBox().findMachine(machineId); - return function.apply(immutableMachine); - - } catch (VBoxException e) { - throw new RuntimeException(String.format("error applying %s to %s: %s", function, machineId, e.getMessage()), - e); - } - } - - /** - * Unlocks the machine and executes the given function, if the machine is registered. Since the - * machine is unlocked it is possible to delete the machine. - *

- * - * @param machineId - * the id of the machine - * @param function - * the function to execute - * @return the result from applying the function to the session. - */ - public T unlockMachineAndApplyOrReturnNullIfNotRegistered(String machineId, Function function) { - try { - return unlockMachineAndApply(machineId, function); - } catch (RuntimeException e) { - VBoxException vbex = Throwables2.getFirstThrowableOfType(e, VBoxException.class); - if (vbex != null && vbex.getMessage().indexOf("not find a registered") == -1) - throw e; - return null; + + void print() { + for (StackTraceElement element : Thread.currentThread().getStackTrace()){ + System.err.println(element.toString()); } } diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java index 33c55a390d..4c082ffc24 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java @@ -29,7 +29,6 @@ import java.util.concurrent.ExecutorService; import javax.inject.Inject; import javax.inject.Named; -import org.jclouds.Constants; import org.jclouds.compute.BaseVersionedServiceLiveTest; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContextFactory; @@ -63,7 +62,7 @@ import com.google.inject.Module; /** * Tests behavior of {@code VirtualBoxClient} * - * @author Adrian Cole + * @author Adrian Cole, David Alves */ @Test(groups = "live", singleThreaded = true, testName = "BaseVirtualBoxClientLiveTest") public class BaseVirtualBoxClientLiveTest extends BaseVersionedServiceLiveTest { @@ -149,8 +148,8 @@ public class BaseVirtualBoxClientLiveTest extends BaseVersionedServiceLiveTest { protected void undoVm(VmSpec vmSpecification) { - machineUtils.unlockMachineAndApplyOrReturnNullIfNotRegistered(vmSpecification.getVmId(), - new UnregisterMachineIfExistsAndDeleteItsMedia(vmSpecification)); + machineUtils.writeLockMachineAndApply(vmSpecification.getVmId(), new UnregisterMachineIfExistsAndDeleteItsMedia( + vmSpecification)); } diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxExperimentLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxExperimentLiveTest.java index 656a61a17f..b4d86b48f4 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxExperimentLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxExperimentLiveTest.java @@ -19,6 +19,7 @@ package org.jclouds.virtualbox.compute; +import static junit.framework.Assert.assertTrue; import static org.testng.Assert.assertEquals; import java.util.Set; @@ -72,6 +73,7 @@ public class VirtualBoxExperimentLiveTest { TemplateOptions.Builder.runScript(AdminAccess.standard())); assertEquals(numNodes, nodes.size(), "wrong number of nodes"); for (NodeMetadata node : nodes) { + assertTrue(node.getGroup().equals("test-launch-cluster")); logger.debug("Created Node: %s", node); SshClient client = context.utils().sshForNode().apply(node); client.connect(); diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java index a4e4d04c95..c062f720b1 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/domain/InstallGuestAdditionsTest.java @@ -35,22 +35,22 @@ import com.google.common.io.Resources; @Test(groups = "unit") public class InstallGuestAdditionsTest { - @Test(enabled = false) - public void testUnixByItself() throws IOException { - InstallGuestAdditions statement = new InstallGuestAdditions("4.1.6"); - assertEquals(statement.render(OsFamily.UNIX), - CharStreams.toString(Resources.newReaderSupplier( - Resources.getResource("test_guest_additions_installer." + ShellToken.SH.to(OsFamily.UNIX)), - Charsets.UTF_8))); - } - - @Test(enabled = false) - public void testUnixInInitScript() throws IOException { - Statement statement = InitScript.builder().name("install_guest_additions") - .run(new InstallGuestAdditions("4.1.6")).build(); - - assertEquals(statement.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier( - Resources.getResource("test_guest_additions_installer_init." + ShellToken.SH.to(OsFamily.UNIX)), - Charsets.UTF_8))); - } +// @Test(enabled = false) +// public void testUnixByItself() throws IOException { +// InstallGuestAdditions statement = new InstallGuestAdditions("4.1.6"); +// assertEquals(statement.render(OsFamily.UNIX), +// CharStreams.toString(Resources.newReaderSupplier( +// Resources.getResource("test_guest_additions_installer." + ShellToken.SH.to(OsFamily.UNIX)), +// Charsets.UTF_8))); +// } +// +// @Test(enabled = false) +// public void testUnixInInitScript() throws IOException { +// Statement statement = InitScript.builder().name("install_guest_additions") +// .run(new InstallGuestAdditions("4.1.6")).build(); +// +// assertEquals(statement.render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier( +// Resources.getResource("test_guest_additions_installer_init." + ShellToken.SH.to(OsFamily.UNIX)), +// Charsets.UTF_8))); +// } } \ No newline at end of file diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java index 4396848ac2..114e23d83e 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java @@ -142,7 +142,7 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest { String vboxVersion = Iterables.get( Splitter.on('r').split(context.getProviderSpecificContext().getBuildVersion()), 0); - assertEquals(vboxVersion, machineUtils.lockSessionOnMachineAndApply(machine.getName(), LockType.Shared, + assertEquals(vboxVersion, machineUtils.sharedLockMachineAndApplyToSession(machine.getName(), new Function() { @Override public String apply(ISession session) { diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadataTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadataTest.java index 390a43e373..221342acb9 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadataTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadataTest.java @@ -24,6 +24,9 @@ import static org.easymock.EasyMock.createNiceMock; import static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_NAME_SEPARATOR; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX; import org.jclouds.compute.domain.NodeMetadata; import org.testng.annotations.Test; @@ -38,22 +41,25 @@ import com.google.common.collect.Iterables; public class IMachineToNodeMetadataTest { + private static final String MASTER_NAME = "mock-image-of-a-server"; + @Test - public void testCreate() throws Exception { + public void testCreateFromMaster() throws Exception { IMachine vm = createNiceMock(IMachine.class); - expect(vm.getName()).andReturn("mocked-vm").anyTimes(); + expect(vm.getName()).andReturn(VIRTUALBOX_IMAGE_PREFIX + MASTER_NAME).anyTimes(); expect(vm.getState()).andReturn(MachineState.PoweredOff).anyTimes(); INetworkAdapter nat = createNiceMock(INetworkAdapter.class); INATEngine natEng = createNiceMock(INATEngine.class); expect(vm.getNetworkAdapter(eq(0l))).andReturn(nat).once(); + expect(vm.getNetworkAdapter(eq(1l))).andReturn(null).once(); expect(nat.getAttachmentType()).andReturn(NetworkAttachmentType.NAT).once(); expect(nat.getNatDriver()).andReturn(natEng).anyTimes(); expect(natEng.getHostIP()).andReturn("127.0.0.1").once(); - expect(natEng.getRedirects()).andReturn(ImmutableList.of("0,1,127.0.0.1,3000,,22")); + expect(natEng.getRedirects()).andReturn(ImmutableList.of("0,1,127.0.0.1,2222,,22")); INetworkAdapter hostOnly = createNiceMock(INetworkAdapter.class); @@ -61,7 +67,45 @@ public class IMachineToNodeMetadataTest { NodeMetadata node = new IMachineToNodeMetadata().apply(vm); - assertEquals("mocked-vm", node.getName()); + assertEquals(MASTER_NAME, node.getName()); + assertEquals(0, node.getPrivateAddresses().size()); + assertEquals(1, node.getPublicAddresses().size()); + assertEquals("127.0.0.1", Iterables.get(node.getPublicAddresses(), 0)); + assertEquals(MastersLoadingCache.MASTER_PORT, node.getLoginPort()); + assertEquals("", node.getGroup()); + } + + @Test + public void testCreateFromNode() throws Exception { + + IMachine vm = createNiceMock(IMachine.class); + + String group = "my-cluster-group"; + String name = "a-name-with-a-code-338"; + + expect(vm.getName()).andReturn( + VIRTUALBOX_NODE_PREFIX + MASTER_NAME + VIRTUALBOX_NODE_NAME_SEPARATOR + group + + VIRTUALBOX_NODE_NAME_SEPARATOR + name).anyTimes(); + expect(vm.getState()).andReturn(MachineState.PoweredOff).anyTimes(); + + INetworkAdapter nat = createNiceMock(INetworkAdapter.class); + INATEngine natEng = createNiceMock(INATEngine.class); + + INetworkAdapter hostOnly = createNiceMock(INetworkAdapter.class); + + expect(vm.getNetworkAdapter(eq(0l))).andReturn(nat).once(); + expect(vm.getNetworkAdapter(eq(1l))).andReturn(hostOnly).once(); + expect(nat.getAttachmentType()).andReturn(NetworkAttachmentType.NAT).once(); + expect(nat.getNatDriver()).andReturn(natEng).anyTimes(); + expect(natEng.getHostIP()).andReturn("127.0.0.1").once(); + expect(natEng.getRedirects()).andReturn(ImmutableList.of("0,1,127.0.0.1,3000,,22")); + + replay(vm, nat, natEng, hostOnly); + + NodeMetadata node = new IMachineToNodeMetadata().apply(vm); + + assertEquals(name, node.getName()); + assertEquals(group, node.getGroup()); assertEquals(1, node.getPrivateAddresses().size()); assertEquals((NodeCreator.VMS_NETWORK + 2), Iterables.get(node.getPrivateAddresses(), 0)); assertEquals(1, node.getPublicAddresses().size()); diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstallerLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstallerLiveTest.java index 30105e2969..c726cf2639 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstallerLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstallerLiveTest.java @@ -41,7 +41,6 @@ import org.testng.annotations.Test; import org.virtualbox_4_1.CleanupMode; import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.ISession; -import org.virtualbox_4_1.LockType; import org.virtualbox_4_1.NetworkAttachmentType; import org.virtualbox_4_1.StorageBus; @@ -74,7 +73,7 @@ public class GuestAdditionsInstallerLiveTest extends .attachISO(0, 0, operatingSystemIso) .attachHardDisk( HardDisk.builder().diskpath(adminDisk(sourceName)).controllerPort(0).deviceSlot(1) - .autoDelete(true).build()).attachISO(1, 1, guestAdditionsIso).build(); + .autoDelete(true).build()).attachISO(1, 0, guestAdditionsIso).build(); VmSpec sourceVmSpec = VmSpec.builder().id(sourceName).name(sourceName) .osTypeId("").memoryMB(512).cleanUpMode(CleanupMode.Full) @@ -111,8 +110,8 @@ public class GuestAdditionsInstallerLiveTest extends machineUtils.applyForMachine(machine.getName(), new LaunchMachineIfNotAlreadyRunning(manager.get(), ExecutionType.GUI, "")); - assertTrue(machineUtils.lockSessionOnMachineAndApply( - machine.getName(), LockType.Shared, + assertTrue(machineUtils.sharedLockMachineAndApplyToSession( + machine.getName(), new Function() { @Override public Boolean apply(ISession session) { diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/statements/GuestAdditionsInstaller.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/statements/GuestAdditionsInstaller.java deleted file mode 100644 index e66f2677f5..0000000000 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/statements/GuestAdditionsInstaller.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.jclouds.virtualbox.statements; - -import javax.annotation.Resource; -import javax.inject.Named; -import javax.inject.Singleton; - -import org.jclouds.compute.ComputeServiceContext; -import org.jclouds.compute.callables.RunScriptOnNode.Factory; -import org.jclouds.compute.domain.ExecResponse; -import org.jclouds.compute.domain.NodeMetadata; -import org.jclouds.compute.options.RunScriptOptions; -import org.jclouds.compute.reference.ComputeServiceConstants; -import org.jclouds.logging.Logger; -import org.jclouds.ssh.SshClient; -import org.jclouds.virtualbox.domain.ExecutionType; -import org.jclouds.virtualbox.functions.CreateAndRegisterMachineFromIsoIfNotAlreadyExists; -import org.jclouds.virtualbox.functions.IMachineToNodeMetadata; -import org.jclouds.virtualbox.functions.LaunchMachineIfNotAlreadyRunning; -import org.jclouds.virtualbox.util.MachineUtils; -import org.virtualbox_4_1.IMachine; -import org.virtualbox_4_1.VirtualBoxManager; - -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.base.Supplier; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.inject.Inject; - -@Singleton -public class GuestAdditionsInstaller implements Function { - - @Resource - @Named(ComputeServiceConstants.COMPUTE_LOGGER) - protected Logger logger = Logger.NULL; - - private final ComputeServiceContext context; - - private final Supplier manager; - private final ExecutionType executionType; - private final MachineUtils machineUtils; - // TODO remove this hardcoded value - private String vboxVersion = "4.1.6"; - - @Inject - public GuestAdditionsInstaller(ComputeServiceContext context, Supplier manager, - CreateAndRegisterMachineFromIsoIfNotAlreadyExists createAndRegisterMachineFromIsoIfNotAlreadyExists, - Predicate installGuestAdditionsViaSshResponds, Function sshClientForIMachine, - ExecutionType executionType, MachineUtils machineUtils, Factory runScriptOnNodeFactory, - Supplier guest) { - this.context = context; - this.manager = manager; - this.executionType = executionType; - this.machineUtils = machineUtils; - } - - @Override - public IMachine apply(String vmName) { - IMachine vm = manager.get().getVBox().findMachine(vmName); - ensureMachineIsLaunched(vmName); - - NodeMetadata vmMetadata = new IMachineToNodeMetadata().apply(vm); - - ListenableFuture execFuture = context.getComputeService().submitScriptOnNode(vmMetadata.getId(), - new InstallGuestAdditions(vboxVersion), RunScriptOptions.NONE); - Futures.getUnchecked(execFuture); - return vm; - } - - private void ensureMachineIsLaunched(String vmName) { - machineUtils.applyForMachine(vmName, new LaunchMachineIfNotAlreadyRunning(manager.get(), executionType, "")); - } - -} \ No newline at end of file diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/statements/InstallGuestAdditionsLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/statements/InstallGuestAdditionsLiveTest.java deleted file mode 100644 index 6513cd740f..0000000000 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/statements/InstallGuestAdditionsLiveTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * 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.statements; - -import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; - -import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -import com.google.common.base.CaseFormat; -import com.google.inject.Injector; - -/** - * @author Andrea Turli - */ -@Test(groups = "live", singleThreaded = true, testName = "InstallGuestAdditionsLiveTest") -public class InstallGuestAdditionsLiveTest extends BaseVirtualBoxClientLiveTest { - - private String vmName; - - @Override - @BeforeClass(groups = "live") - public void setupClient() { - super.setupClient(); - vmName = VIRTUALBOX_IMAGE_PREFIX - + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass() - .getSimpleName()); - - vmName = "jclouds-image-create-and-install-vm-live-test"; - } - - public void testInstallGuestAdditionsOnTheMachine() throws Exception { - Injector injector = context.utils().injector(); - injector.getInstance(GuestAdditionsInstaller.class).apply(vmName); - } - -} \ No newline at end of file diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/statements/InstallGuestAdditionsTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/statements/InstallGuestAdditionsTest.java new file mode 100644 index 0000000000..910dd1da65 --- /dev/null +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/statements/InstallGuestAdditionsTest.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.statements; + +import static junit.framework.Assert.assertEquals; + +import org.jclouds.scriptbuilder.domain.OsFamily; +import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest; +import org.jclouds.virtualbox.domain.StorageController; +import org.jclouds.virtualbox.domain.VmSpec; +import org.testng.annotations.Test; +import org.virtualbox_4_1.CleanupMode; +import org.virtualbox_4_1.StorageBus; + +/** + * @author Andrea Turli, David Alves + */ +@Test(testName = "InstallGuestAdditionsTest") +public class InstallGuestAdditionsTest extends BaseVirtualBoxClientLiveTest { + + public void testIsoPresent() { + StorageController ideController = StorageController.builder().name("IDE Controller").bus(StorageBus.IDE) + .attachISO(1, 0, "VBoxGuestAdditions_").build(); + + VmSpec vmSpecification = VmSpec.builder().id("").name("").memoryMB(512).osTypeId("").controller(ideController) + .forceOverwrite(true).cleanUpMode(CleanupMode.Full).build(); + + InstallGuestAdditions installer = new InstallGuestAdditions(vmSpecification, "4.1.8"); + String scripts = installer.render(OsFamily.UNIX); + assertEquals("installModuleAssistantIfNeeded || return 1\n" + "mount -t iso9660 /dev/sr1 /mnt\n" + + "/mnt/VBoxLinuxAdditions.run\n" + "umount /mnt\n", scripts); + } + + public void testIsoNotPresent() { + StorageController ideController = StorageController.builder().name("IDE Controller").bus(StorageBus.IDE).build(); + + VmSpec vmSpecification = VmSpec.builder().id("").name("").memoryMB(512).osTypeId("").controller(ideController) + .forceOverwrite(true).cleanUpMode(CleanupMode.Full).build(); + + InstallGuestAdditions installer = new InstallGuestAdditions(vmSpecification, "4.1.8"); + String scripts = installer.render(OsFamily.UNIX); + assertEquals( + "installModuleAssistantIfNeeded || return 1\n" + + "setupPublicCurl || return 1\n" + + "(mkdir -p /tmp/ && cd /tmp/ && [ ! -f VBoxGuestAdditions_4.1.8.iso ] && curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -C - -X GET http://download.virtualbox.org/virtualbox/4.1.8/VBoxGuestAdditions_4.1.8.iso >VBoxGuestAdditions_4.1.8.iso)\n" + + "mount -o loop /tmp/VBoxGuestAdditions_4.1.8.iso /mnt\n" + + "/mnt/VBoxLinuxAdditions.run\n" + "umount /mnt\n", scripts); + } + +} \ No newline at end of file