Merge pull request #844 from andreaturli/virtualbox

issue 384: improved ISession management; added ubuntu 10.04.4 support;
This commit is contained in:
Adrian Cole 2012-09-19 09:01:16 -07:00
commit 9b5073710a
40 changed files with 1330 additions and 554 deletions

View File

@ -38,7 +38,7 @@
<test.virtualbox.endpoint>http://localhost:18083/</test.virtualbox.endpoint>
<test.virtualbox.api-version>4.1.4</test.virtualbox.api-version>
<test.virtualbox.build-version>4.1.20r80170</test.virtualbox.build-version>
<test.virtualbox.identity>administrator</test.virtualbox.identity>
<test.virtualbox.identity>${user.name}</test.virtualbox.identity>
<test.virtualbox.credential>CHANGE_ME</test.virtualbox.credential>
<test.virtualbox.template>osFamily=UBUNTU,osVersionMatches=12.04.1,os64Bit=true,osArchMatches=amd64,loginUser=toor:password,authenticateSudo=true</test.virtualbox.template>
<jclouds.osgi.export>org.jclouds.virtualbox*;version="${project.version}"</jclouds.osgi.export>

View File

@ -20,12 +20,12 @@ package org.jclouds.virtualbox;
import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAULT_DIR;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_CREDENTIAL;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_IDENTITY;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGES_DESCRIPTOR;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_PRECONFIGURATION_URL;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_WORKINGDIR;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_MEMORY;
import java.io.File;
import java.net.URI;
@ -74,22 +74,17 @@ public class VirtualBoxApiMetadata extends BaseApiMetadata {
+ "initrd=/install/initrd.gz -- <Enter>");
String workingDir = System.getProperty("test.virtualbox.workingDir", VIRTUALBOX_DEFAULT_DIR);
properties.put(VIRTUALBOX_WORKINGDIR, workingDir);
String ram = System.getProperty(VIRTUALBOX_GUEST_MEMORY, "1024");
properties.put(VIRTUALBOX_GUEST_MEMORY, ram);
String yamlDescriptor = System.getProperty("test.virtualbox.image.descriptor.yaml", VIRTUALBOX_WORKINGDIR
+ File.separator + "images.yaml");
properties.put(VIRTUALBOX_IMAGES_DESCRIPTOR, yamlDescriptor);
properties.put(VIRTUALBOX_PRECONFIGURATION_URL, "http://10.0.2.2:23232/preseed.cfg");
properties.put(VIRTUALBOX_GUEST_IDENTITY, "toor");
properties.put(VIRTUALBOX_GUEST_CREDENTIAL, "password");
properties.setProperty(TEMPLATE,
String.format("osFamily=UBUNTU,osVersionMatches=12.04.1,os64Bit=true,osArchMatches=amd64,loginUser=%s:%s,authenticateSudo=true",
properties.getProperty(VIRTUALBOX_GUEST_IDENTITY),
properties.getProperty(VIRTUALBOX_GUEST_CREDENTIAL)));
properties.setProperty(TEMPLATE, "osFamily=UBUNTU,osVersionMatches=12.04.1,os64Bit=true,osArchMatches=amd64");
return properties;
}

View File

@ -28,6 +28,7 @@ import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.inject.Inject;
@ -46,6 +47,7 @@ import org.jclouds.virtualbox.domain.Master;
import org.jclouds.virtualbox.domain.NodeSpec;
import org.jclouds.virtualbox.domain.YamlImage;
import org.jclouds.virtualbox.functions.admin.UnregisterMachineIfExistsAndForceDeleteItsMedia;
import org.jclouds.virtualbox.util.MachineController;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISession;
@ -62,6 +64,7 @@ import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Uninterruptibles;
import com.google.inject.Singleton;
/**
@ -82,17 +85,20 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
private final LoadingCache<Image, Master> mastersLoader;
private final Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator;
private final Function<IMachine, Image> imachineToImage;
private final MachineController machineController;
@Inject
public VirtualBoxComputeServiceAdapter(Supplier<VirtualBoxManager> manager,
Supplier<Map<Image, YamlImage>> imagesMapper, LoadingCache<Image, Master> mastersLoader,
Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator,
Function<IMachine, Image> imachineToImage) {
Function<IMachine, Image> imachineToImage,
MachineController machineController) {
this.manager = checkNotNull(manager, "manager");
this.imagesToYamlImages = imagesMapper.get();
this.mastersLoader = mastersLoader;
this.cloneCreator = cloneCreator;
this.imachineToImage = imachineToImage;
this.machineController = machineController;
}
@Override
@ -199,7 +205,11 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
public synchronized void destroyNode(String vmName) {
IMachine machine = manager.get().getVBox().findMachine(vmName);
powerDownMachine(machine);
new UnregisterMachineIfExistsAndForceDeleteItsMedia().apply(machine);
try {
new UnregisterMachineIfExistsAndForceDeleteItsMedia().apply(machine);
} catch (Exception e) {
logger.error("Machine (%s) not unregistered!", vmName);
}
}
@Override
@ -247,21 +257,10 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
logger.debug("vm was already powered down: ", machine.getId());
return;
}
logger.debug("powering down vm: ", machine.getId());
ISession machineSession = manager.get().openMachineSession(machine);
IProgress progress = machineSession.getConsole().powerDown();
progress.waitForCompletion(-1);
machineSession.unlockMachine();
while (!machine.getSessionState().equals(SessionState.Unlocked)) {
try {
logger.info("waiting for unlocking session - session state: " + machine.getSessionState());
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
logger.debug("powering down vm: %s", machine.getName());
machineController.ensureMachineHasPowerDown(machine.getName());
} catch (Exception e) {
logger.error(e, "problem in powering down the %s", machine.getName());
throw Throwables.propagate(e);
}
}

View File

@ -236,4 +236,5 @@ public class VirtualBoxComputeServiceContextModule extends
protected Map<MachineState, Image.Status> toPortableImageStatus() {
return toPortableImageStatus;
}
}

View File

@ -50,6 +50,8 @@ public interface VirtualBoxConstants {
public static final String VIRTUALBOX_MACHINE_CREDENTIAL = "jclouds.virtualbox.credential";
public static final String VIRTUALBOX_MACHINE_LOCATION = "jclouds.virtualbox.location";
public static final String VIRTUALBOX_GUEST_MEMORY = "jclouds.virtualbox.guest.memory";
public static final String VIRTUALBOX_HOST_ID = "jclouds.virtualbox.hostid";
@ -62,7 +64,7 @@ public interface VirtualBoxConstants {
public static final String VIRTUALBOX_PROVIDER = "virtualbox";
public static final String VIRTUALBOX_GUEST_IDENTITY = "jclouds.virtualbox.guest.identity";
public static final String VIRTUALBOX_GUEST_CREDENTIAL = "jclouds.virtualbox.guest.credential";
public static final String GUEST_OS_PASSWORD = "guestPassword";
public static final String GUEST_OS_USER = "guestUser";
}

View File

@ -21,6 +21,8 @@ package org.jclouds.virtualbox.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.domain.LoginCredentials;
import com.google.common.base.Objects;
/**
@ -32,6 +34,7 @@ public class MasterSpec {
private VmSpec vmSpec;
private IsoSpec isoSpec;
private NetworkSpec networkSpec;
private LoginCredentials loginCredentials;
public static Builder builder() {
return new Builder();
@ -42,6 +45,7 @@ public class MasterSpec {
private VmSpec vmSpec;
private IsoSpec isoSpec;
private NetworkSpec networkSpec;
private LoginCredentials loginCredentials;
public Builder vm(VmSpec vmSpec) {
this.vmSpec = vmSpec;
@ -58,19 +62,25 @@ public class MasterSpec {
return this;
}
public Builder credentials(LoginCredentials loginCredentials) {
this.loginCredentials = loginCredentials;
return this;
}
public MasterSpec build() {
return new MasterSpec(vmSpec, isoSpec, networkSpec);
return new MasterSpec(vmSpec, isoSpec, networkSpec, loginCredentials);
}
}
private MasterSpec(VmSpec vmSpec, IsoSpec isoSpec, NetworkSpec networkSpec) {
private MasterSpec(VmSpec vmSpec, IsoSpec isoSpec, NetworkSpec networkSpec, LoginCredentials loginCredentials) {
checkNotNull(vmSpec, "vmSpec");
checkNotNull(isoSpec, "isoSpec");
checkNotNull(networkSpec, "networkSpec");
this.vmSpec = vmSpec;
this.isoSpec = isoSpec;
this.networkSpec = networkSpec;
this.loginCredentials = loginCredentials;
}
public VmSpec getVmSpec() {
@ -84,6 +94,10 @@ public class MasterSpec {
public NetworkSpec getNetworkSpec() {
return networkSpec;
}
public LoginCredentials getLoginCredentials() {
return loginCredentials;
}
@Override
public boolean equals(Object o) {

View File

@ -28,12 +28,13 @@ public class NetworkInterfaceCard {
private final long slot;
private final NetworkAdapter networkAdapter;
private final String hostInterfaceName;
private final boolean enabled;
public NetworkInterfaceCard(long slot, NetworkAdapter networkAdapter, String hostInterfaceName) {
public NetworkInterfaceCard(long slot, NetworkAdapter networkAdapter, String hostInterfaceName, boolean enabled) {
this.slot = checkNotNull(slot, "slot");
this.networkAdapter = checkNotNull(networkAdapter, "networkAdapter");
this.hostInterfaceName = hostInterfaceName;
this.enabled = enabled;
}
public static Builder builder() {
@ -45,6 +46,7 @@ public class NetworkInterfaceCard {
private long slot = 0L;
private NetworkAdapter networkAdapter;
private String hostInterfaceName;
private boolean enabled = true;
public Builder slot(long slot) {
checkArgument(slot >= 0 && slot < 4, "must be 0, 1, 2, 3: %s", slot);
@ -62,10 +64,16 @@ public class NetworkInterfaceCard {
String hostInterfaceName) {
this.hostInterfaceName = hostInterfaceName;
return this;
}
}
public Builder enabled(
boolean enabled) {
this.enabled = enabled;
return this;
}
public NetworkInterfaceCard build() {
return new NetworkInterfaceCard(slot, networkAdapter, hostInterfaceName);
return new NetworkInterfaceCard(slot, networkAdapter, hostInterfaceName, enabled);
}
}
@ -79,7 +87,11 @@ public class NetworkInterfaceCard {
public String getHostInterfaceName() {
return hostInterfaceName;
}
}
public boolean isEnabled() {
return enabled;
}
@Override
public boolean equals(Object o) {
@ -89,14 +101,15 @@ public class NetworkInterfaceCard {
NetworkInterfaceCard other = (NetworkInterfaceCard) o;
return Objects.equal(slot,
other.slot) &&
Objects.equal(networkAdapter, other.networkAdapter);
Objects.equal(networkAdapter, other.networkAdapter)
&& Objects.equal(enabled, other.enabled);
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(slot, networkAdapter);
return Objects.hashCode(slot, networkAdapter, enabled);
}
@Override
@ -104,6 +117,7 @@ public class NetworkInterfaceCard {
return "NetworkInterfaceCard{slot="+
slot +
", networkAdapter=" + networkAdapter +
", enabled=" + enabled +
'}';
}

View File

@ -42,7 +42,7 @@ public class VmSpec {
private final Set<StorageController> controllers;
private final CleanupMode cleanupMode;
public VmSpec(String vmId, String vmName, String osTypeId, long memory, boolean forceOverwrite,
public VmSpec(String vmId, String vmName, String osTypeId, long memory, String guestUser, String guestPassword, boolean forceOverwrite,
Set<StorageController> controllers, CleanupMode cleanupMode) {
this.vmId = checkNotNull(vmId, "vmId");
this.vmName = checkNotNull(vmName, "vmName");
@ -67,6 +67,8 @@ public class VmSpec {
private String osTypeId = "";
private boolean forceOverwrite = true;
private long memory;
private String guestUser;
private String guestPassword;
private CleanupMode cleanUpMode;
public Builder controller(StorageController controller) {
@ -103,13 +105,24 @@ public class VmSpec {
this.cleanUpMode = cleanupMode;
return this;
}
public Builder guestUser(String guestUser) {
this.guestUser = guestUser;
return this;
}
public Builder guestPassword(String guestPassword) {
this.guestPassword = guestPassword;
return this;
}
public VmSpec build() {
checkNotNull(name, "name");
checkNotNull(id, "id");
checkArgument(memory > 0, "Memory must be set");
return new VmSpec(id, name, osTypeId, memory, forceOverwrite, controllers, cleanUpMode);
return new VmSpec(id, name, osTypeId, memory, guestUser, guestPassword, forceOverwrite, controllers, cleanUpMode);
}
}
public String getVmId() {
@ -162,7 +175,8 @@ public class VmSpec {
@Override
public String toString() {
return "VmSpecification{" + "vmName='" + vmName + '\'' + ", osTypeId='" + osTypeId + '\'' + ", memory='" + memory
+ '\'' + ", vmId='" + vmId + '\'' + ", forceOverwrite=" + forceOverwrite + ", controllers="
+ controllers + ", cleanupMode=" + cleanupMode + '}';
+ '\'' + ", vmId='" + vmId + '\'' + '\''
+ ", forceOverwrite=" + forceOverwrite + ", controllers="
+ controllers + ", cleanupMode=" + cleanupMode + '}';
}
}

View File

@ -27,6 +27,7 @@ import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageBuilder;
import org.jclouds.compute.domain.OperatingSystem;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.domain.LoginCredentials;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
@ -137,13 +138,16 @@ public class YamlImage {
public Image apply(YamlImage arg0) {
if (arg0 == null)
return null;
OsFamily family = parseOsFamilyOrUnrecognized(arg0.os_family);
OperatingSystem operatingSystem = OperatingSystem.builder().description(arg0.os_description).family(family)
.version(arg0.os_version).is64Bit(arg0.os_64bit).arch(arg0.os_arch).build();
return new ImageBuilder().id(arg0.id).name(arg0.name).description(arg0.description)
.operatingSystem(operatingSystem).status(Image.Status.AVAILABLE).build();
.operatingSystem(operatingSystem).status(Image.Status.AVAILABLE)
.defaultCredentials(new LoginCredentials(arg0.username, arg0.credential, null, true))
.build();
}
};

View File

@ -46,7 +46,7 @@ public class AttachBridgedAdapterToMachine implements Function<IMachine, Void> {
iNetworkAdapter.setAdapterType(Am79C973);
iNetworkAdapter.setMACAddress(networkInterfaceCard.getNetworkAdapter().getMacAddress());
iNetworkAdapter.setBridgedInterface(networkInterfaceCard.getHostInterfaceName());
iNetworkAdapter.setEnabled(true);
iNetworkAdapter.setEnabled(networkInterfaceCard.isEnabled());
machine.saveSettings();
return null;
}

View File

@ -45,7 +45,7 @@ public class AttachHostOnlyAdapter implements Function<IMachine, Void> {
iNetworkAdapter.setAdapterType(Am79C973);
iNetworkAdapter.setMACAddress(networkInterfaceCard.getNetworkAdapter().getMacAddress());
iNetworkAdapter.setHostOnlyInterface(networkInterfaceCard.getHostInterfaceName());
iNetworkAdapter.setEnabled(true);
iNetworkAdapter.setEnabled(networkInterfaceCard.isEnabled());
machine.saveSettings();
return null;
}

View File

@ -55,7 +55,7 @@ public class AttachNATAdapterToMachineIfNotAlreadyExists implements Function<IMa
throw e;
}
}
iNetworkAdapter.setEnabled(true);
iNetworkAdapter.setEnabled(networkInterfaceCard.isEnabled());
machine.saveSettings();
return null;
}

View File

@ -19,9 +19,11 @@
package org.jclouds.virtualbox.functions;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.GUEST_OS_PASSWORD;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.GUEST_OS_USER;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.Resource;
import javax.inject.Named;
@ -62,8 +64,6 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements Fu
private final String workingDir;
private final MachineUtils machineUtils;
private final ReentrantLock lock = new ReentrantLock();
@Inject
public CloneAndRegisterMachineFromIMachineIfNotAlreadyExists(Supplier<VirtualBoxManager> manager,
@Named(VirtualBoxConstants.VIRTUALBOX_WORKINGDIR) String workingDir, MachineUtils machineUtils) {
@ -125,6 +125,13 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements Fu
for (NetworkInterfaceCard networkInterfaceCard : networkSpec.getNetworkInterfaceCards()) {
new AttachNicToMachine(vmSpec.getVmName(), machineUtils).apply(networkInterfaceCard);
}
// set only once the creds for this machine, same coming from its master
logger.debug(">> storing guest credentials on vm %s as extra data", clonedMachine.getName());
String masterUsername = master.getExtraData(GUEST_OS_USER);
String masterPassword = master.getExtraData(GUEST_OS_PASSWORD);
clonedMachine.setExtraData(GUEST_OS_USER, masterUsername);
clonedMachine.setExtraData(GUEST_OS_PASSWORD, masterPassword);
return clonedMachine;
}

View File

@ -21,9 +21,12 @@ package org.jclouds.virtualbox.functions;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.transform;
import static org.jclouds.scriptbuilder.domain.Statements.call;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.GUEST_OS_PASSWORD;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.GUEST_OS_USER;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_PRECONFIGURATION_URL;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.inject.Named;
@ -49,10 +52,10 @@ import org.virtualbox_4_1.IMediumAttachment;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.Uninterruptibles;
import com.google.inject.Inject;
@Singleton
@ -70,7 +73,7 @@ public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
private final MachineController machineController;
private final String version;
private final String preconfigurationUrl;
@Inject
public CreateAndInstallVm(
CreateAndRegisterMachineFromIsoIfNotAlreadyExists CreateAndRegisterMachineFromIsoIfNotAlreadyExists,
@ -92,49 +95,60 @@ public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
public IMachine apply(MasterSpec masterSpec) {
VmSpec vmSpec = masterSpec.getVmSpec();
IsoSpec isoSpec = masterSpec.getIsoSpec();
String vmName = vmSpec.getVmName();
IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists.apply(masterSpec);
String masterName = vmSpec.getVmName();
IMachine masterMachine = createAndRegisterMachineFromIsoIfNotAlreadyExists.apply(masterSpec);
// Launch machine and wait for it to come online
machineController.ensureMachineIsLaunched(vmName);
machineController.ensureMachineIsLaunched(masterName);
String installationKeySequence = isoSpec.getInstallationKeySequence().replace("PRECONFIGURATION_URL",
preconfigurationUrl);
configureOsInstallationWithKeyboardSequence(vmName, installationKeySequence);
configureOsInstallationWithKeyboardSequence(masterName, installationKeySequence);
// the OS installation is a long process: let's delay the check for ssh of 30 sec
try {
Thread.sleep(30000l);
} catch (InterruptedException e) {
Throwables.propagate(e);
}
// the OS installation is a long process: let's delay the check for ssh of 40 sec
Uninterruptibles.sleepUninterruptibly(40, TimeUnit.SECONDS);
masterMachine.setExtraData(GUEST_OS_USER, masterSpec.getLoginCredentials().getUser());
masterMachine.setExtraData(GUEST_OS_PASSWORD, masterSpec.getLoginCredentials().getPassword());
SshClient client = sshClientForIMachine.apply(vm);
logger.debug(">> awaiting installation to finish node(%s)", vmName);
checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh", vmName);
NodeMetadata nodeMetadata = imachineToNodeMetadata.apply(vm);
SshClient client = sshClientForIMachine.apply(masterMachine);
logger.debug(">> awaiting installation to finish node(%s)", masterName);
checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh", masterName);
NodeMetadata nodeMetadata = imachineToNodeMetadata.apply(masterMachine);
logger.debug(">> awaiting post-installation actions on vm: %s", vmName);
logger.debug(">> awaiting post-installation actions on vm: %s", masterName);
ListenableFuture<ExecResponse> execCleanup = machineUtils.runScriptOnNode(nodeMetadata,
call("cleanupUdevIfNeeded"), RunScriptOptions.NONE);
ExecResponse cleanupResponse = Futures.getUnchecked(execCleanup);
checkState(cleanupResponse.getExitStatus() == 0);
logger.debug(">> awaiting installation of guest additions on vm: %s", vmName);
logger.debug(">> awaiting installation of guest additions on vm: %s", masterName);
ListenableFuture<ExecResponse> execInstallGA = machineUtils.runScriptOnNode(nodeMetadata,
new InstallGuestAdditions(vmSpec, version), RunScriptOptions.NONE);
ExecResponse gaInstallationResponse = Futures.getUnchecked(execInstallGA);
checkState(gaInstallationResponse.getExitStatus() == 0);
machineController.ensureMachineIsShutdown(vmName);
Iterable<IMediumAttachment> mediumAttachments = Iterables.filter(vm.getMediumAttachmentsOfController("IDE Controller"),
new Predicate<IMediumAttachment>() {
public boolean apply(IMediumAttachment in) {
return in.getMedium() != null && in.getMedium().getDeviceType().equals(DeviceType.DVD);
}
});
machineController.ensureMachineIsShutdown(masterName);
// detach DVD and ISOs, if needed
Iterable<IMediumAttachment> mediumAttachments = Iterables.filter(
masterMachine.getMediumAttachmentsOfController("IDE Controller"),
new Predicate<IMediumAttachment>() {
public boolean apply(IMediumAttachment in) {
return in.getMedium() != null
&& in.getMedium().getDeviceType()
.equals(DeviceType.DVD);
}
});
for (IMediumAttachment iMediumAttachment : mediumAttachments) {
machineUtils.writeLockMachineAndApply(vm.getName(), new DetachDistroMediumFromMachine(
iMediumAttachment.getController(), iMediumAttachment.getPort(), iMediumAttachment.getDevice()));
}
return vm;
logger.debug("Detach %s from (%s)", iMediumAttachment.getMedium()
.getName(), masterMachine.getName());
machineUtils.writeLockMachineAndApply(
masterMachine.getName(),
new DetachDistroMediumFromMachine(iMediumAttachment
.getController(), iMediumAttachment.getPort(),
iMediumAttachment.getDevice()));
}
return masterMachine;
}
private void configureOsInstallationWithKeyboardSequence(String vmName, String installationKeySequence) {

View File

@ -77,30 +77,31 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExists implements Functi
}
@Override
public IMachine apply(MasterSpec launchSpecification) {
public IMachine apply(MasterSpec masterSpec) {
final IVirtualBox vBox = manager.get().getVBox();
String vmName = launchSpecification.getVmSpec().getVmName();
String vmId = launchSpecification.getVmSpec().getVmId();
String vmName = masterSpec.getVmSpec().getVmName();
String vmId = masterSpec.getVmSpec().getVmId();
try {
vBox.findMachine(vmId);
throw new IllegalStateException("Machine " + vmName + " is already registered.");
} catch (VBoxException e) {
if (machineNotFoundException(e))
return createMachine(vBox, launchSpecification);
return createMachine(vBox, masterSpec);
else
throw e;
}
}
private IMachine createMachine(IVirtualBox vBox, MasterSpec machineSpec) {
VmSpec vmSpec = machineSpec.getVmSpec();
private IMachine createMachine(IVirtualBox vBox, MasterSpec masterSpec) {
VmSpec vmSpec = masterSpec.getVmSpec();
String settingsFile = vBox.composeMachineFilename(vmSpec.getVmName(), workingDir);
IMachine newMachine = vBox.createMachine(settingsFile, vmSpec.getVmName(), vmSpec.getOsTypeId(),
vmSpec.getVmId(), vmSpec.isForceOverwrite());
manager.get().getVBox().registerMachine(newMachine);
ensureConfiguration(machineSpec);
ensureConfiguration(masterSpec);
return newMachine;
}

View File

@ -19,6 +19,8 @@
package org.jclouds.virtualbox.functions;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.GUEST_OS_PASSWORD;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.GUEST_OS_USER;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_NAME_SEPARATOR;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX;
@ -37,7 +39,7 @@ import org.jclouds.domain.LocationScope;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.logging.Logger;
import org.jclouds.virtualbox.util.MachineUtils;
import org.jclouds.virtualbox.util.NetworkUtils;
import org.testng.collections.Lists;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.INetworkAdapter;
@ -58,12 +60,13 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
protected Logger logger = Logger.NULL;
private final Map<MachineState, Status> toPortableNodeStatus;
private final MachineUtils machineUtils;
private final NetworkUtils networkUtils;
@Inject
public IMachineToNodeMetadata(Map<MachineState, NodeMetadata.Status> toPortableNodeStatus, MachineUtils machineUtils) {
public IMachineToNodeMetadata(Map<MachineState, NodeMetadata.Status> toPortableNodeStatus,
NetworkUtils networkUtils) {
this.toPortableNodeStatus = toPortableNodeStatus;
this.machineUtils = machineUtils;
this.networkUtils = networkUtils;
}
@Override
@ -95,8 +98,10 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
nodeState = Status.UNRECOGNIZED;
nodeMetadataBuilder.status(nodeState);
nodeMetadataBuilder = getIpAddresses(vm, nodeMetadataBuilder);
LoginCredentials loginCredentials = new LoginCredentials("toor", "password", null, true);
String guestOsUser = vm.getExtraData(GUEST_OS_USER);
String guestOsPassword = vm.getExtraData(GUEST_OS_PASSWORD);
LoginCredentials loginCredentials = new LoginCredentials(guestOsUser, guestOsPassword, null, true);
nodeMetadataBuilder.credentials(loginCredentials);
return nodeMetadataBuilder.build();
@ -104,7 +109,7 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
private NodeMetadataBuilder getIpAddresses(IMachine vm, NodeMetadataBuilder nodeMetadataBuilder) {
List<String> publicIpAddresses = Lists.newArrayList();
List<String> privateIpAddresses = Lists.newArrayList();
for(long slot = 0; slot < 4; slot ++) {
INetworkAdapter adapter = vm.getNetworkAdapter(slot);
if(adapter != null) {
@ -123,16 +128,15 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
publicIpAddresses.add(hostAddress);
nodeMetadataBuilder.loginPort(inPort);
}
//privateIpAddresses.add((NodeCreator.VMS_NETWORK + ipTermination) + "");
}
// TODO this could be a public and private address
} else if (adapter.getAttachmentType() == NetworkAttachmentType.Bridged) {
String clientIpAddress = machineUtils.getIpAddressFromFirstNIC(vm.getName());
//privateIpAddresses.add(clientIpAddress);
publicIpAddresses.add(clientIpAddress);
// TODO quick test first
String clientIpAddress = networkUtils.getIpAddressFromNicSlot(vm.getName(), adapter.getSlot());
privateIpAddresses.add(clientIpAddress);
} else if (adapter.getAttachmentType() == NetworkAttachmentType.HostOnly) {
String clientIpAddress = machineUtils.getIpAddressFromFirstNIC(vm.getName());
// TODO quick test first
String clientIpAddress = networkUtils.getIpAddressFromNicSlot(vm.getName(), adapter.getSlot());
publicIpAddresses.add(clientIpAddress);
}
}

View File

@ -19,36 +19,24 @@
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.VirtualBoxConstants.VIRTUALBOX_GUEST_CREDENTIAL;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_IDENTITY;
import java.util.List;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.GUEST_OS_PASSWORD;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.GUEST_OS_USER;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.callables.RunScriptOnNode;
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.domain.LoginCredentials;
import org.jclouds.logging.Logger;
import org.jclouds.ssh.SshClient;
import org.jclouds.virtualbox.VirtualBoxApiMetadata;
import org.jclouds.virtualbox.domain.BridgedIf;
import org.jclouds.virtualbox.statements.GetIPAddressFromMAC;
import org.jclouds.virtualbox.statements.ScanNetworkWithPing;
import org.jclouds.virtualbox.util.MachineUtils;
import org.jclouds.virtualbox.util.NetworkUtils;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.INetworkAdapter;
import org.virtualbox_4_1.NetworkAttachmentType;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
import com.google.common.net.HostAndPort;
import com.google.inject.Inject;
@ -61,36 +49,30 @@ public class IMachineToSshClient implements Function<IMachine, SshClient> {
protected Logger logger = Logger.NULL;
private final SshClient.Factory sshClientFactory;
private final RunScriptOnNode.Factory scriptRunnerFactory;
private final Supplier<NodeMetadata> hostSupplier;
private final MachineUtils machineUtils;
private final NetworkUtils networkUtils;
@Inject
public IMachineToSshClient(SshClient.Factory sshClientFactory,
RunScriptOnNode.Factory scriptRunnerFactory,
Supplier<NodeMetadata> hostSupplier, MachineUtils machineUtils) {
NetworkUtils networkUtils) {
this.sshClientFactory = sshClientFactory;
this.scriptRunnerFactory = scriptRunnerFactory;
this.hostSupplier = hostSupplier;
this.machineUtils = machineUtils;
this.networkUtils = networkUtils;
}
@Override
public SshClient apply(final IMachine vm) {
INetworkAdapter networkAdapter = vm.getNetworkAdapter(0L);
public SshClient apply(final IMachine vm) {
INetworkAdapter networkAdapter = vm.getNetworkAdapter(0L);
SshClient client = null;
checkNotNull(networkAdapter);
SshClient client = null;
checkNotNull(networkAdapter);
String clientIpAddress = null;
String sshPort = "22";
String clientIpAddress = null;
String sshPort = "22";
String guestIdentity = vm.getExtraData(GUEST_OS_USER);
String guestCredential = vm.getExtraData(GUEST_OS_PASSWORD);
String guestIdentity = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_IDENTITY);
String guestCredential = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_CREDENTIAL);
LoginCredentials loginCredentials = LoginCredentials.builder()
.user(guestIdentity)
.password(guestCredential).authenticateSudo(true)
.build();
LoginCredentials loginCredentials = LoginCredentials.builder()
.user(guestIdentity).password(guestCredential)
.authenticateSudo(true).build();
if (networkAdapter.getAttachmentType()
.equals(NetworkAttachmentType.NAT)) {
@ -109,11 +91,10 @@ public class IMachineToSshClient implements Function<IMachine, SshClient> {
}
} else if (networkAdapter.getAttachmentType().equals(
NetworkAttachmentType.Bridged)) {
String network = "1.1.1.1";
clientIpAddress = getIpAddressFromBridgedNIC(networkAdapter, network);
clientIpAddress = networkUtils.getIpAddressFromNicSlot(vm.getName(), networkAdapter.getSlot());
} else if (networkAdapter.getAttachmentType().equals(
NetworkAttachmentType.HostOnly)) {
clientIpAddress = machineUtils.getIpAddressFromFirstNIC(vm.getName());
clientIpAddress = networkUtils.getIpAddressFromNicSlot(vm.getName(), networkAdapter.getSlot());
}
checkNotNull(clientIpAddress, "clientIpAddress");
@ -124,28 +105,4 @@ public class IMachineToSshClient implements Function<IMachine, SshClient> {
return client;
}
private String getIpAddressFromBridgedNIC(INetworkAdapter networkAdapter,
String network) {
// RetrieveActiveBridgedInterfaces
List<BridgedIf> activeBridgedInterfaces = new RetrieveActiveBridgedInterfaces(scriptRunnerFactory).apply(hostSupplier.get());
BridgedIf activeBridgedIf = checkNotNull(Iterables.get(activeBridgedInterfaces, 0), "activeBridgedInterfaces");
network = activeBridgedIf.getIpAddress();
// scan ip
RunScriptOnNode ipScanRunScript = scriptRunnerFactory.create(
hostSupplier.get(), new ScanNetworkWithPing(network),
RunScriptOptions.NONE);
ExecResponse execResponse = ipScanRunScript.init().call();
checkState(execResponse.getExitStatus() == 0);
// retrieve ip from mac
RunScriptOnNode getIpFromMACAddressRunScript = scriptRunnerFactory
.create(hostSupplier.get(), new GetIPAddressFromMAC(
networkAdapter.getMACAddress()),
RunScriptOptions.NONE);
ExecResponse ipExecResponse = getIpFromMACAddressRunScript.init()
.call();
checkState(ipExecResponse.getExitStatus() == 0);
return checkNotNull(ipExecResponse.getOutput(), "ipAddress");
}
}

View File

@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.inject.Inject;
@ -31,30 +32,33 @@ import javax.inject.Singleton;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.virtualbox.util.MachineUtils;
import org.jclouds.virtualbox.util.MachineNameOrIdAndNicSlot;
import org.jclouds.virtualbox.util.NetworkUtils;
import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Strings;
import com.google.common.base.Supplier;
import com.google.common.cache.AbstractLoadingCache;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.Uninterruptibles;
/**
* A {@link LoadingCache} for ip addresses. If the requested ip address has been
* previously extracted this returns it, if not it calls vbox api.
*
* @author andrea turli
* @author Andrea Turli
*
*/
@Singleton
public class IpAddressesLoadingCache extends
AbstractLoadingCache<String, String> {
AbstractLoadingCache<MachineNameOrIdAndNicSlot, String> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final Map<String, String> masters = Maps.newHashMap();
private final Map<MachineNameOrIdAndNicSlot, String> masters = Maps.newHashMap();
private final Supplier<VirtualBoxManager> manager;
@Inject
@ -63,27 +67,23 @@ public class IpAddressesLoadingCache extends
}
@Override
public synchronized String get(String idOrName) throws ExecutionException {
if (masters.containsKey(idOrName)) {
return masters.get(idOrName);
public synchronized String get(MachineNameOrIdAndNicSlot machineNameOrIdAndNicPort) throws ExecutionException {
if (masters.containsKey(machineNameOrIdAndNicPort)) {
return masters.get(machineNameOrIdAndNicPort);
}
String currentIp = "", previousIp = "";
int count = 0;
while (count < 3) {
currentIp = "";
while (!MachineUtils.isIpv4(currentIp)) {
currentIp = manager.get().getVBox().findMachine(idOrName)
.getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP");
String query = String.format("/VirtualBox/GuestInfo/Net/%s/V4/IP", machineNameOrIdAndNicPort.getSlotText());
String currentIp = "";
while (!NetworkUtils.isIpv4(currentIp)) {
currentIp = manager.get().getVBox().findMachine(machineNameOrIdAndNicPort.getMachineNameOrId())
.getGuestPropertyValue(query);
if(!Strings.nullToEmpty(currentIp).isEmpty())
logger.debug("Found IP address %s for '%s' at slot %s", currentIp,
machineNameOrIdAndNicPort.getMachineNameOrId(),
machineNameOrIdAndNicPort.getSlotText());
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
}
if (previousIp.equals(currentIp)) {
count++;
}
previousIp = currentIp;
}
masters.put(idOrName, currentIp);
masters.put(machineNameOrIdAndNicPort, currentIp);
return currentIp;
}
@ -92,4 +92,9 @@ public class IpAddressesLoadingCache extends
return masters.get((String) key);
}
@Override
public void invalidate(Object key) {
masters.remove(key);
}
}

View File

@ -75,11 +75,6 @@ public class LaunchMachineIfNotAlreadyRunning implements Function<IMachine, ISes
final IProgress progress = machine
.launchVMProcess(session, type.stringValue(), environment);
progress.waitForCompletion(-1);
try {
Thread.sleep(3000l);
} catch (InterruptedException e) {
propagate(e);
}
} catch (VBoxException e) {
ErrorCode errorCode = ErrorCode.valueOf(e);
switch (errorCode) {

View File

@ -50,6 +50,7 @@ import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.location.Provider;
import org.jclouds.logging.Logger;
import org.jclouds.rest.annotations.BuildVersion;
@ -68,6 +69,7 @@ import org.jclouds.virtualbox.domain.VmSpec;
import org.jclouds.virtualbox.domain.YamlImage;
import org.jclouds.virtualbox.functions.admin.PreseedCfgServer;
import org.jclouds.virtualbox.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.virtualbox.util.NetworkUtils;
import org.testng.collections.Lists;
import org.virtualbox_4_1.CleanupMode;
import org.virtualbox_4_1.IMachine;
@ -76,6 +78,7 @@ import org.virtualbox_4_1.StorageBus;
import org.virtualbox_4_1.VBoxException;
import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.CaseFormat;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
@ -98,9 +101,6 @@ import com.google.common.net.HostAndPort;
@Singleton
public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
// TODO parameterize
public static final int MASTER_PORT = 2222;
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
@ -197,18 +197,17 @@ public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
server.start(preconfigurationUrl, currentImage.preseed_cfg);
}
} catch (URISyntaxException e1) {
logger.error("Cannot start the preseed server", e);
throw e;
}
MasterSpec masterSpec = buildMasterSpecFromYaml(currentImage,
vmName);
// create the master machine if it can't be found
masterMachine = masterCreatorAndInstaller.apply(masterSpec);
// build the master
master = Master.builder().machine(masterMachine)
.spec(masterSpec).build();
} else {
logger.error("Problem during master creation", e);
throw e;
}
} finally {
@ -241,15 +240,16 @@ public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
.attachISO(0, 0, localIsoUrl).attachHardDisk(hardDisk)
.attachISO(1, 0, guestAdditionsIso).build();
VmSpec vmSpecification = VmSpec.builder().id(currentImage.id)
.name(vmName).memoryMB(512).osTypeId("")
VmSpec vmSpecification = VmSpec.builder().id(currentImage.id)
.name(vmName).memoryMB(512).osTypeId(getOsTypeId(currentImage.os_family, currentImage.os_64bit))
.controller(ideController).forceOverwrite(true)
.guestUser(currentImage.username).guestPassword(currentImage.credential)
.cleanUpMode(CleanupMode.Full).build();
NetworkAdapter networkAdapter = NetworkAdapter
.builder()
.networkAttachmentType(NetworkAttachmentType.NAT)
.tcpRedirectRule(providerSupplier.get().getHost(), MASTER_PORT,
.tcpRedirectRule(providerSupplier.get().getHost(), NetworkUtils.MASTER_PORT,
"", 22).build();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard
@ -257,7 +257,7 @@ public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
NetworkSpec networkSpec = NetworkSpec.builder()
.addNIC(networkInterfaceCard).build();
return MasterSpec
.builder()
.vm(vmSpecification)
@ -267,10 +267,12 @@ public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
.installationScript(
installationKeySequence.replace("HOSTNAME",
vmSpecification.getVmName())).build())
.network(networkSpec).build();
.network(networkSpec)
.credentials(new LoginCredentials(currentImage.username, currentImage.credential, null, true))
.build();
}
@Override
@Override
public synchronized Master getIfPresent(Object key) {
checkArgument(key instanceof Image,
"this cache is for entries who's keys are Images");
@ -315,4 +317,8 @@ public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
return file.getAbsolutePath();
}
private String getOsTypeId(String os_family, boolean os_64bit) {
String osFamily = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, os_family);
return os_64bit ? osFamily + "_64" : osFamily;
}
}

View File

@ -21,52 +21,42 @@ 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.compute.options.RunScriptOptions.Builder.runAsRoot;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_CREDENTIAL;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_IDENTITY;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.GUEST_OS_PASSWORD;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.GUEST_OS_USER;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_MEMORY;
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.net.URI;
import java.util.List;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.callables.RunScriptOnNode.Factory;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Provider;
import org.jclouds.rest.annotations.Credential;
import org.jclouds.rest.annotations.Identity;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.virtualbox.VirtualBoxApiMetadata;
import org.jclouds.logging.Logger;
import org.jclouds.virtualbox.config.VirtualBoxComputeServiceContextModule;
import org.jclouds.virtualbox.domain.CloneSpec;
import org.jclouds.virtualbox.domain.Master;
import org.jclouds.virtualbox.domain.NetworkAdapter;
import org.jclouds.virtualbox.domain.NetworkInterfaceCard;
import org.jclouds.virtualbox.domain.NetworkSpec;
import org.jclouds.virtualbox.domain.NodeSpec;
import org.jclouds.virtualbox.domain.VmSpec;
import org.jclouds.virtualbox.statements.DeleteGShadowLock;
import org.jclouds.virtualbox.statements.EnableNetworkInterface;
import org.jclouds.virtualbox.util.MachineController;
import org.jclouds.virtualbox.util.MachineUtils;
import org.jclouds.virtualbox.util.NetworkUtils;
import org.virtualbox_4_1.CleanupMode;
import org.virtualbox_4_1.HostNetworkInterfaceType;
import org.virtualbox_4_1.IDHCPServer;
import org.virtualbox_4_1.IHostNetworkInterface;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.LockType;
import org.virtualbox_4_1.NetworkAttachmentType;
import org.virtualbox_4_1.VirtualBoxManager;
@ -74,7 +64,6 @@ import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@ -87,67 +76,65 @@ import com.google.common.collect.Iterables;
*/
@Singleton
public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials<IMachine>> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final Supplier<VirtualBoxManager> manager;
private final Function<CloneSpec, IMachine> cloner;
private final MachineUtils machineUtils;
private final MachineController machineController;
private final Factory runScriptOnNodeFactory;
private final Supplier<NodeMetadata> host;
private final Supplier<URI> providerSupplier;
private final String username;
private final String password;
private int ram = 512;
private final String guestIdentity = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_IDENTITY);
private final String guestCredential = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_CREDENTIAL);
private final NetworkUtils networkUtils;
private final int ram;
@Inject
public NodeCreator(Supplier<VirtualBoxManager> manager, Function<CloneSpec, IMachine> cloner, Factory runScriptOnNodeFactory,
public NodeCreator(Supplier<VirtualBoxManager> manager, Function<CloneSpec, IMachine> cloner,
MachineUtils machineUtils, RunScriptOnNode.Factory scriptRunnerFactory, MachineController machineController,
Supplier<NodeMetadata> host,
@Provider Supplier<URI> providerSupplier,
@Nullable @Identity String identity,
@Nullable @Credential String credential) {
NetworkUtils networkUtils,
@Named(VIRTUALBOX_GUEST_MEMORY) String ram) {
this.manager = manager;
this.cloner = cloner;
this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
this.networkUtils = networkUtils;
this.machineUtils = machineUtils;
this.machineController = machineController;
this.host = checkNotNull(host, "host");
this.providerSupplier = checkNotNull(providerSupplier,
"endpoint to virtualbox websrvd is needed");
this.username = identity;
this.password = credential;
this.ram = Integer.valueOf(ram);
}
@Override
public synchronized NodeAndInitialCredentials<IMachine> apply(NodeSpec nodeSpec) {
checkNotNull(nodeSpec, "NodeSpec");
Master master = checkNotNull(nodeSpec.getMaster(), "Master");
if (master.getMachine().getCurrentSnapshot() != null) {
ISession session;
try {
session = manager.get().openMachineSession(master.getMachine());
session = manager.get().getSessionObject();
master.getMachine().lockMachine(session, LockType.Write);
IProgress progress = session.getConsole().deleteSnapshot(master.getMachine().getCurrentSnapshot().getId());
progress.waitForCompletion(-1);
session.unlockMachine();
} catch (Exception e) {
throw new RuntimeException("error opening vbox machine session: " + e.getMessage(), e);
}
IProgress progress = session.getConsole().deleteSnapshot(master.getMachine().getCurrentSnapshot().getId());
progress.waitForCompletion(-1);
session.unlockMachine();
logger.debug("Deleted an existing snapshot from %s", master.getMachine().getName());
}
String masterNameWithoutPrefix = master.getMachine().getName().replace(VIRTUALBOX_IMAGE_PREFIX, "");
String cloneName = VIRTUALBOX_NODE_PREFIX + masterNameWithoutPrefix + VIRTUALBOX_NODE_NAME_SEPARATOR
+ nodeSpec.getTag() + VIRTUALBOX_NODE_NAME_SEPARATOR + nodeSpec.getName();
if (nodeSpec.getTemplate() != null && nodeSpec.getTemplate().getHardware() != null
&& nodeSpec.getTemplate().getHardware().getRam() > 0) {
ram = nodeSpec.getTemplate().getHardware().getRam();
}
IMachine masterMachine = master.getMachine();
String username = masterMachine.getExtraData(GUEST_OS_USER);
String password = masterMachine.getExtraData(GUEST_OS_PASSWORD);
VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(ram)
.guestUser(username).guestPassword(password)
.cleanUpMode(CleanupMode.Full)
.forceOverwrite(true).build();
.forceOverwrite(true).build();
// case 'vbox host is localhost': NAT + HOST-ONLY
NetworkSpec networkSpec = createNetworkSpecWhenVboxIsLocalhost();
NetworkSpec networkSpec = networkUtils.createNetworkSpecWhenVboxIsLocalhost();
Optional<NetworkInterfaceCard> optionalNatIfaceCard = Iterables.tryFind(
networkSpec.getNetworkInterfaceCards(),
new Predicate<NetworkInterfaceCard>() {
@ -161,9 +148,10 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
CloneSpec cloneSpec = CloneSpec.builder().linked(true).master(master.getMachine()).network(networkSpec)
.vm(cloneVmSpec).build();
logger.debug("Cloning a new guest an existing snapshot from %s ...", master.getMachine().getName());
IMachine cloned = cloner.apply(cloneSpec);
machineController.ensureMachineIsLaunched(cloneVmSpec.getVmName());
// IMachineToNodeMetadata produces the final ip's but these need to be set before so we build a
// NodeMetadata just for the sake of running the gshadow and setip scripts
NodeMetadata partialNodeMetadata = buildPartialNodeMetadata(cloned);
@ -172,139 +160,37 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
machineUtils.runScriptOnNode(partialNodeMetadata, new DeleteGShadowLock(), RunScriptOptions.NONE);
if(optionalNatIfaceCard.isPresent())
machineUtils.runScriptOnNode(partialNodeMetadata, new EnableNetworkInterface(optionalNatIfaceCard.get()), RunScriptOptions.NONE);
checkState(networkUtils.enableNetworkInterface(partialNodeMetadata, optionalNatIfaceCard.get()) == true,
"cannot enable Nat Interface");
LoginCredentials credentials = partialNodeMetadata.getCredentials();
return new NodeAndInitialCredentials<IMachine>(cloned,
cloneName, LoginCredentials.builder()
.user(guestIdentity)
.password(guestCredential)
.authenticateSudo(true)
.build());
cloneName, credentials);
}
private NodeMetadata buildPartialNodeMetadata(IMachine clone) {
NodeMetadataBuilder nodeMetadataBuilder = new NodeMetadataBuilder();
nodeMetadataBuilder.id(clone.getName());
nodeMetadataBuilder.status(VirtualBoxComputeServiceContextModule.toPortableNodeStatus.get(clone.getState()));
nodeMetadataBuilder.publicAddresses(ImmutableSet.of(machineUtils.getIpAddressFromFirstNIC(clone.getName())));
LoginCredentials loginCredentials = new LoginCredentials(guestIdentity, guestCredential, null, true);
long slot = findSlotForNetworkAttachment(clone, NetworkAttachmentType.HostOnly);
nodeMetadataBuilder.publicAddresses(ImmutableSet.of(networkUtils.getIpAddressFromNicSlot(clone.getName(), slot)));
String guestOsUser = clone.getExtraData(GUEST_OS_USER);
String guestOsPassword = clone.getExtraData(GUEST_OS_PASSWORD);
LoginCredentials loginCredentials = new LoginCredentials(guestOsUser, guestOsPassword, null, true);
nodeMetadataBuilder.credentials(loginCredentials);
return nodeMetadataBuilder.build();
}
private NetworkSpec createNetworkSpecWhenVboxIsLocalhost() {
NetworkAdapter natAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
.build();
NetworkInterfaceCard natIfaceCard = NetworkInterfaceCard.builder()
.addNetworkAdapter(natAdapter)
.slot(1L)
.build();
NetworkAdapter hostOnlyAdapter = NetworkAdapter.builder()
.networkAttachmentType(NetworkAttachmentType.HostOnly)
.build();
// create new hostOnly interface if needed, otherwise use the one already there with dhcp enabled ...
String hostOnlyIfName = getHostOnlyIfOrCreate();
NetworkInterfaceCard hostOnlyIfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(hostOnlyAdapter)
.addHostInterfaceName(hostOnlyIfName).slot(0L).build();
return createNetworkSpecForHostOnlyNATNICs(natIfaceCard, hostOnlyIfaceCard);
}
private NetworkSpec createNetworkSpecForHostOnlyNATNICs(NetworkInterfaceCard natIfaceCard,
NetworkInterfaceCard hostOnlyIfaceCard) {
return NetworkSpec.builder()
.addNIC(natIfaceCard)
.addNIC(hostOnlyIfaceCard)
.build();
}
private String getHostOnlyIfOrCreate() {
IHostNetworkInterface availableHostInterfaceIf = returnExistingHostNetworkInterfaceWithDHCPenabledOrNull(manager
.get().getVBox().getHost().getNetworkInterfaces());
if (availableHostInterfaceIf==null) {
final String hostOnlyIfName = createHostOnlyIf();
assignDHCPtoHostOnlyInterface(hostOnlyIfName);
return hostOnlyIfName;
} else {
return availableHostInterfaceIf.getName();
private long findSlotForNetworkAttachment(IMachine clone, NetworkAttachmentType networkAttachmentType) {
long slot = -1, i = 0;
while (slot == -1 && i < 4) {
if(clone.getNetworkAdapter(i).getAttachmentType().equals(networkAttachmentType))
slot = i;
i++;
}
checkState(slot!=-1);
return slot;
}
private void assignDHCPtoHostOnlyInterface(final String hostOnlyIfName) {
List<IHostNetworkInterface> availableNetworkInterfaces = manager.get().getVBox().getHost()
.getNetworkInterfaces();
IHostNetworkInterface iHostNetworkInterfaceWithHostOnlyIfName = Iterables.getOnlyElement(Iterables.filter(availableNetworkInterfaces, new Predicate<IHostNetworkInterface>() {
@Override
public boolean apply(IHostNetworkInterface iHostNetworkInterface) {
return iHostNetworkInterface.getName().equals(hostOnlyIfName);
}
}));
String hostOnlyIfIpAddress = iHostNetworkInterfaceWithHostOnlyIfName.getIPAddress();
String dhcpIpAddress = hostOnlyIfIpAddress.substring(0, hostOnlyIfIpAddress.lastIndexOf(".")) + ".254";
String dhcpNetmask = "255.255.255.0";
String dhcpLowerIp = hostOnlyIfIpAddress.substring(0, hostOnlyIfIpAddress.lastIndexOf(".")) + ".2";
String dhcpUpperIp = hostOnlyIfIpAddress.substring(0, hostOnlyIfIpAddress.lastIndexOf(".")) + ".253";
NodeMetadata hostNodeMetadata = getHostNodeMetadata();
ExecResponse response = runScriptOnNodeFactory
.create(hostNodeMetadata,
Statements.exec(String
.format("VBoxManage dhcpserver add --ifname %s --ip %s --netmask %s --lowerip %s --upperip %s --enable",
hostOnlyIfName, dhcpIpAddress, dhcpNetmask, dhcpLowerIp, dhcpUpperIp)), runAsRoot(false).wrapInInitScript(false)).init().call();
checkState(response.getExitStatus()==0);
}
private String createHostOnlyIf() {
final String hostOnlyIfName;
NodeMetadata hostNodeMetadata = getHostNodeMetadata();
ExecResponse createHostOnlyResponse = runScriptOnNodeFactory
.create(hostNodeMetadata, Statements.exec("VBoxManage hostonlyif create"),
runAsRoot(false).wrapInInitScript(false)).init().call();
String output = createHostOnlyResponse.getOutput();
checkState(createHostOnlyResponse.getExitStatus()==0);
checkState(output.contains("'"), "cannot create hostonlyif");
hostOnlyIfName = output.substring(output.indexOf("'") + 1, output.lastIndexOf("'"));
return hostOnlyIfName;
}
private NodeMetadata getHostNodeMetadata() {
NodeMetadata hostNodeMetadata = NodeMetadataBuilder
.fromNodeMetadata(host.get())
.credentials(LoginCredentials.builder().user(username).password(password).build())
.publicAddresses(
ImmutableList.of(providerSupplier.get().getHost()))
.build();
return hostNodeMetadata;
}
private IHostNetworkInterface returnExistingHostNetworkInterfaceWithDHCPenabledOrNull(Iterable<IHostNetworkInterface> availableNetworkInterfaces) {
checkNotNull(availableNetworkInterfaces);
return Iterables.getFirst(filterAvailableNetworkInterfaceByHostOnlyAndDHCPenabled(availableNetworkInterfaces), null);
}
/**
* @param availableNetworkInterfaces
* @param hostOnlyIfIpAddress
* @return
*/
private Iterable<IHostNetworkInterface> filterAvailableNetworkInterfaceByHostOnlyAndDHCPenabled(Iterable<IHostNetworkInterface> availableNetworkInterfaces) {
Iterable<IHostNetworkInterface> filteredNetworkInterfaces = Iterables.filter(availableNetworkInterfaces, new Predicate<IHostNetworkInterface>() {
@Override
public boolean apply(IHostNetworkInterface iHostNetworkInterface) {
// this is an horrible workaround cause iHostNetworkInterface.getDhcpEnabled is working only for windows host
boolean match = false;
List<IDHCPServer> availableDHCPservers = manager.get().getVBox().getDHCPServers();
for (IDHCPServer idhcpServer : availableDHCPservers) {
if(idhcpServer.getEnabled() && idhcpServer.getNetworkName().equals(iHostNetworkInterface.getNetworkName()))
match = true;
}
return iHostNetworkInterface.getInterfaceType().equals(HostNetworkInterfaceType.HostOnly) &&
match;
}
});
return filteredNetworkInterfaces;
}
}

View File

@ -19,13 +19,13 @@
package org.jclouds.virtualbox.functions;
import static com.google.common.base.Predicates.in;
import static com.google.common.base.Throwables.propagate;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Lists.partition;
import static org.jclouds.compute.reference.ComputeServiceConstants.COMPUTE_LOGGER;
import static org.jclouds.virtualbox.settings.KeyboardScancodes.SPECIAL_KEYBOARD_BUTTON_MAP_LIST;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.inject.Named;
@ -34,6 +34,7 @@ import org.jclouds.logging.Logger;
import org.virtualbox_4_1.ISession;
import com.google.common.base.Function;
import com.google.common.util.concurrent.Uninterruptibles;
class SendScancodes implements Function<ISession, Void> {
@ -56,9 +57,9 @@ class SendScancodes implements Function<ISession, Void> {
logger.debug("List of scancodes sent: ", maxOrLess);
assert (codesSent == maxOrLess.size());
if (any(maxOrLess, in(SPECIAL_KEYBOARD_BUTTON_MAP_LIST.values()))) {
sleepOrPropagateInterrupt(300);
Uninterruptibles.sleepUninterruptibly(300, TimeUnit.MILLISECONDS);
} else {
sleepOrPropagateInterrupt(50);
Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
}
}
return null;
@ -68,12 +69,4 @@ class SendScancodes implements Function<ISession, Void> {
public String toString() {
return "sendScancodes(" + scancodes + ")";
}
public void sleepOrPropagateInterrupt(long ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
throw propagate(e);
}
}
}

View File

@ -19,6 +19,8 @@
package org.jclouds.virtualbox.functions;
import java.util.concurrent.TimeUnit;
import org.jclouds.logging.Logger;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IProgress;
@ -30,6 +32,7 @@ import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.Uninterruptibles;
/**
* @author Andrea Turli
@ -93,7 +96,7 @@ public class TakeSnapshotIfNotAlreadyAttached implements Function<IMachine, ISna
snapshotName, snapshotDesc, machine.getName());
throw Throwables.propagate(e);
}
Thread.sleep(1000L);
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
continue;
}
logger.error(e, "Problem creating snapshot %s (description: %s) from machine %s", snapshotName,

View File

@ -85,22 +85,8 @@ public class StartVBoxIfNotAlreadyRunning implements Supplier<VirtualBoxManager>
public synchronized void start() {
URI provider = providerSupplier.get();
NodeMetadata hostNodeMetadata = hardcodedHostToHostNodeMetadata.apply(host.get());
// kill previously started vboxwebsrv (possibly dirty session)
List<Statement> statements = Lists.newArrayList();
statements.add(Statements.findPid("vboxwebsrv"));
statements.add(Statements.kill());
StatementList statementList = new StatementList(statements);
if (socketTester.apply(HostAndPort.fromParts(provider.getHost(),
provider.getPort()))) {
logger.debug(String.format("shutting down previously started vboxwewbsrv at %s", provider));
ExecResponse execResponse = runScriptOnNodeFactory
.create(hostNodeMetadata, statementList, runAsRoot(false))
.init().call();
if(execResponse.getExitStatus()!=0)
throw new RuntimeException("Cannot execute jclouds");
}
cleanUpHost(provider, hostNodeMetadata);
logger.debug("disabling password access");
runScriptOnNodeFactory
.create(
@ -131,6 +117,24 @@ public class StartVBoxIfNotAlreadyRunning implements Supplier<VirtualBoxManager>
logger.warn("manager is not in unlocked state "
+ manager.getSessionObject().getState());
}
private void cleanUpHost(URI provider, NodeMetadata hostNodeMetadata) {
// kill previously started vboxwebsrv (possibly dirty session)
List<Statement> statements = Lists.newArrayList();
statements.add(Statements.findPid("vboxwebsrv"));
statements.add(Statements.kill());
StatementList statementList = new StatementList(statements);
if (socketTester.apply(HostAndPort.fromParts(provider.getHost(),
provider.getPort()))) {
logger.debug(String.format("shutting down previously started vboxwewbsrv at %s", provider));
ExecResponse execResponse = runScriptOnNodeFactory
.create(hostNodeMetadata, statementList, runAsRoot(false))
.init().call();
if(execResponse.getExitStatus()!=0)
throw new RuntimeException("Cannot execute jclouds");
}
}
@Override
public VirtualBoxManager get() {

View File

@ -89,7 +89,7 @@ public class UnregisterMachineIfExistsAndForceDeleteItsMedia implements Function
if (!filteredMediaToBeDeleted.isEmpty()) {
try {
IProgress deletion = machine.delete(filteredMediaToBeDeleted);
deletion.waitForCompletion(-1);
deletion.waitForCompletion(100);
} catch (Exception e) {
logger.error(e, "Problem in deleting the media attached to %s", machine.getName());
Throwables.propagate(e);

View File

@ -87,12 +87,7 @@ public class InstallGuestAdditions implements Statement {
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("service vboxadd setup")); //
statements.add(exec("VBoxService")); //
statements.add(exec(String.format("echo VBoxService > /etc/rc.local"))); //
statements.add(exec(String.format("echo exit 0 >> /etc/rc.local"))); //
statements.add(exec(String.format("umount %s", mountPoint)));
statements.add(exec(String.format("%s%s", mountPoint, "/VBoxLinuxAdditions.run --nox11"))); //
return statements;
}

View File

@ -20,6 +20,9 @@ package org.jclouds.virtualbox.util;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
@ -28,15 +31,25 @@ import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.virtualbox.domain.ExecutionType;
import org.jclouds.virtualbox.functions.LaunchMachineIfNotAlreadyRunning;
import org.virtualbox_4_1.AdditionsFacilityStatus;
import org.virtualbox_4_1.AdditionsFacilityType;
import org.virtualbox_4_1.AdditionsRunLevelType;
import org.virtualbox_4_1.IAdditionsFacility;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.LockType;
import org.virtualbox_4_1.MachineState;
import org.virtualbox_4_1.SessionState;
import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.Uninterruptibles;
import com.google.inject.Inject;
/**
@ -65,27 +78,57 @@ public class MachineController {
public ISession ensureMachineIsLaunched(String vmName) {
ISession session = null;
while (!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.Running)) {
IMachine machine = manager.get().getVBox().findMachine(vmName);
while (!machine.getState().equals(MachineState.Running)) {
try {
session = machineUtils.applyForMachine(vmName, new LaunchMachineIfNotAlreadyRunning(manager.get(),
executionType, ""));
session = machineUtils.applyForMachine(vmName,
new LaunchMachineIfNotAlreadyRunning(manager.get(),
executionType, ""));
} catch (RuntimeException e) {
if (e.getMessage().contains(
"org.virtualbox_4_1.VBoxException: VirtualBox error: The given session is busy (0x80BB0007)")) {
if (e.getMessage()
.contains(
"org.virtualbox_4_1.VBoxException: VirtualBox error: The given session is busy (0x80BB0007)")) {
throw e;
} else if (e.getMessage().contains("VirtualBox error: The object is not ready")) {
} else if (e.getMessage().contains(
"VirtualBox error: The object is not ready")) {
continue;
} else {
throw e;
}
}
}
// for scancode
Uninterruptibles.sleepUninterruptibly(5, TimeUnit.SECONDS);
String guestAdditionsInstalled = machineUtils.sharedLockMachineAndApplyToSession(vmName,
new Function<ISession, String>() {
@Override
public String apply(ISession session) {
int attempts = 0;
String guestAdditionsInstalled = null;
while (!!session.getConsole().getGuest()
.getAdditionsVersion().isEmpty() && attempts < 3) {
Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
guestAdditionsInstalled = session.getConsole().getGuest()
.getAdditionsVersion();
attempts++;
}
return guestAdditionsInstalled;
}
});
if(!Strings.nullToEmpty(guestAdditionsInstalled).isEmpty()) {
waitVBoxServiceIsActive(vmName);
}
return checkNotNull(session, "session");
}
public ISession ensureMachineHasPowerDown(String vmName) {
ISession session = manager.get().getSessionObject();
while (!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.PoweredOff)) {
IMachine machine = manager.get().getVBox().findMachine(vmName);
while (!machine.getState().equals(MachineState.PoweredOff)) {
try {
session = machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared,
new Function<ISession, ISession>() {
@ -97,9 +140,6 @@ public class MachineController {
}
});
} catch (RuntimeException e) {
// sometimes the machine might be powered of between the while
// test and the call to
// lockSessionOnMachineAndApply
if (e.getMessage().contains("Invalid machine state: PoweredOff")) {
throw e;
} else if (e.getMessage().contains("VirtualBox error: The object is not ready")) {
@ -109,6 +149,7 @@ public class MachineController {
}
}
}
safeCheckMachineIsUnlocked(machine);
return checkNotNull(session, "session");
}
@ -117,6 +158,7 @@ public class MachineController {
* http://askubuntu.com/questions/82015/shutting-down-ubuntu-server-running-in-headless-virtualbox
*/
public ISession ensureMachineIsShutdown(String vmName) {
IMachine machine = manager.get().getVBox().findMachine(vmName);
ISession session = machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared,
new Function<ISession, ISession>() {
@Override
@ -125,19 +167,12 @@ public class MachineController {
return session;
}
});
int count = 0;
while (!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.PoweredOff) && count < 10) {
try {
Thread.sleep(500l * count);
} catch (InterruptedException e) {
Throwables.propagate(e);
}
count++;
}
safeCheckMachineIsUnlocked(machine);
return checkNotNull(session, "session");
}
public void ensureMachineIsPaused(String vmName) {
IMachine machine = manager.get().getVBox().findMachine(vmName);
while (!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.Paused)) {
try {
machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, new Function<ISession, Void>() {
@ -160,9 +195,11 @@ public class MachineController {
}
}
}
safeCheckMachineIsUnlocked(machine);
}
public void ensureMachineIsResumed(String vmName) {
IMachine machine = manager.get().getVBox().findMachine(vmName);
while (!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.Running)) {
try {
machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, new Function<ISession, Void>() {
@ -185,6 +222,58 @@ public class MachineController {
}
}
}
safeCheckMachineIsUnlocked(machine);
}
private void safeCheckMachineIsUnlocked(IMachine machine) {
int guard = 0;
while (!machine.getSessionState().equals(SessionState.Unlocked)) {
if(guard >= 5) {
logger.warn("Machine session (%s) possibly still unlocked!!!", machine.getName());
break;
}
logger.debug("Machine session (%s) not unlocked - wait ...", machine.getName());
Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
guard++;
}
logger.debug("Machine session (%s) is %s", machine.getName(), machine.getSessionState());
}
private void waitVBoxServiceIsActive(String vmName) {
machineUtils.sharedLockMachineAndApplyToSession(vmName, new Function<ISession, Void>() {
@Override
public Void apply(ISession session) {
session.getConsole().getGuest().setStatisticsUpdateInterval(1l);
while (!session.getConsole().getGuest().getAdditionsStatus(AdditionsRunLevelType.Userland)) {
Uninterruptibles.sleepUninterruptibly(200, TimeUnit.MILLISECONDS);
}
List<IAdditionsFacility> facilities = session.getConsole().getGuest().getFacilities();
while (facilities.size() != 4) {
Uninterruptibles.sleepUninterruptibly(200, TimeUnit.MILLISECONDS);
facilities = session.getConsole().getGuest().getFacilities();
}
facilities = session.getConsole().getGuest().getFacilities();
Optional<IAdditionsFacility> vboxServiceFacility = Optional.absent();
while (!vboxServiceFacility.isPresent()) {
vboxServiceFacility = Iterables.tryFind(session.getConsole().getGuest().getFacilities(),
new Predicate<IAdditionsFacility>() {
@Override
public boolean apply(IAdditionsFacility additionsFacility) {
return additionsFacility.getType().equals(AdditionsFacilityType.VBoxService);
};
});
}
while(!vboxServiceFacility.get().getStatus().equals(AdditionsFacilityStatus.Active)) {
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
}
Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);
return null;
}
});
}
}

View File

@ -0,0 +1,132 @@
package org.jclouds.virtualbox.util;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.io.Serializable;
import com.google.common.base.Objects;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
/**
* An immutable representation of a MachineNameOrId and NIC port.
*
* <p>Example usage:
* <pre>
* MachineNameOrIdAndNicSlot mp = MachineNameOrIdAndNicSlot.fromString("myMachine:1");
* hp.getMachineNameOrId(); // returns "myMachine"
* hp.getSlot(); // returns 1
* hp.toString(); // returns "myMachine:1"
* </pre>
*
* @author Andrea Turli
*/
public final class MachineNameOrIdAndNicSlot implements Serializable {
private static final String SEPARATOR = ":";
/** IMachine name or id*/
private final String machineNameOrId;
/** Validated NIC slot number in the range [0..3] */
private final long slot;
private MachineNameOrIdAndNicSlot(String machineNameOrId, long slot) {
this.machineNameOrId = machineNameOrId;
this.slot = slot;
}
public String getMachineNameOrId() {
return machineNameOrId;
}
public boolean hasSlot() {
return slot >= 0;
}
public long getSlot() {
checkState(hasSlot());
return slot;
}
public String getSlotText() {
checkState(hasSlot());
return String.valueOf(slot);
}
public static MachineNameOrIdAndNicSlot fromParts(String machineNameOrId, long slot) {
checkArgument(isValidSlot(slot));
return new MachineNameOrIdAndNicSlot(checkNotNull(machineNameOrId, "machineNameOrId"), slot);
}
public static MachineNameOrIdAndNicSlot fromString(
String machineNameOrIdAndNicSlotString) {
checkNotNull(machineNameOrIdAndNicSlotString);
String machineNameOrId = null;
String nicSlotString = null;
Iterable<String> splittedString = Splitter.on(SEPARATOR).split(
machineNameOrIdAndNicSlotString);
checkState(Iterables.size(splittedString) == 2);
machineNameOrId = Iterables.get(splittedString, 0);
nicSlotString = Iterables.get(splittedString, 1);
long slot = -1;
if (nicSlotString != null) {
checkArgument(!nicSlotString.startsWith("+"),
"Unparseable slot number: %s", nicSlotString);
try {
slot = Long.parseLong(nicSlotString);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Unparseable slot number: "
+ nicSlotString);
}
checkArgument(isValidSlot(slot), "Slot number out of range: %s",
nicSlotString);
}
return new MachineNameOrIdAndNicSlot(machineNameOrId, slot);
}
public MachineNameOrIdAndNicSlot withDefaultSlot(int defaultSlot) {
checkArgument(isValidSlot(defaultSlot));
if (hasSlot() || slot == defaultSlot) {
return this;
}
return new MachineNameOrIdAndNicSlot(machineNameOrId, defaultSlot);
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other instanceof MachineNameOrIdAndNicSlot) {
MachineNameOrIdAndNicSlot that = (MachineNameOrIdAndNicSlot) other;
return Objects.equal(this.machineNameOrId, that.machineNameOrId)
&& this.slot == that.slot;
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(machineNameOrId, slot);
}
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("machineNameOrId", machineNameOrId)
.add("nicSlot", slot)
.toString();
}
private static boolean isValidSlot(long slot) {
return slot >= 0l && slot <= 3l;
}
private static final long serialVersionUID = 0;
}

View File

@ -21,9 +21,7 @@ package org.jclouds.virtualbox.util;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.inject.Named;
@ -48,8 +46,8 @@ import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.Uninterruptibles;
import com.google.inject.Inject;
/**
@ -61,6 +59,8 @@ import com.google.inject.Inject;
@Singleton
public class MachineUtils {
public final String IP_V4_ADDRESS_PATTERN = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
@ -71,14 +71,13 @@ public class MachineUtils {
private final Supplier<VirtualBoxManager> manager;
private final Factory scriptRunner;
private final IpAddressesLoadingCache ipAddressesLoadingCache;
@Inject
public MachineUtils(Supplier<VirtualBoxManager> manager, RunScriptOnNode.Factory scriptRunner,
IpAddressesLoadingCache ipAddressesLoadingCache) {
this.manager = manager;
this.scriptRunner = scriptRunner;
this.ipAddressesLoadingCache = ipAddressesLoadingCache;
}
public ListenableFuture<ExecResponse> runScriptOnNode(NodeMetadata metadata, Statement statement,
@ -183,7 +182,7 @@ public class MachineUtils {
* <p/>
* Unlocks the machine before returning.
*
* Tries to obtain a lock 5 times before giving up waiting 1 sec between tries. When no machine
* Tries to obtain a lock 15 times before giving up waiting 1 sec between tries. When no machine
* is found null is returned.
*
* @param type
@ -196,30 +195,27 @@ public class MachineUtils {
*/
protected <T> T lockSessionOnMachineAndApply(String machineId, LockType type, Function<ISession, T> function) {
int retries = 15;
ISession session = lockSession(machineId, type, retries);
ISession session = checkNotNull(lockSession(machineId, type, retries), "session");
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 {
if (session != null && session.getState().equals(SessionState.Locked))
session.unlockMachine();
if (session.getState().equals(SessionState.Locked)) {
session.unlockMachine();
while (!session.getState().equals(SessionState.Unlocked)) {
logger.debug("Session not unlocked - wait ...");
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
}
}
}
}
private ISession lockSession(String machineId, LockType type, int retries) {
int count = 0;
ISession session;
IMachine immutableMachine = manager.get().getVBox().findMachine(machineId);
try {
session = manager.get().openMachineSession(immutableMachine);
if (session.getState().equals(SessionState.Locked))
return checkNotNull(session, "session");
} catch (Exception e) {
logger.debug("machine %s is not locked). Error: %s", immutableMachine.getName(), e.getMessage());
}
ISession session = null;
while (true) {
try {
@ -237,10 +233,7 @@ public class MachineUtils {
throw new RuntimeException(String.format("error locking %s with %s lock: %s", machineId, type,
e.getMessage()), e);
}
try {
Thread.sleep(count * 1000L);
} catch (InterruptedException e1) {
}
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
}
}
checkState(session.getState().equals(SessionState.Locked));
@ -278,24 +271,4 @@ public class MachineUtils {
|| e.getMessage().contains("Could not find a registered machine with UUID {");
}
public String getIpAddressFromFirstNIC(String machineName) {
try {
return ipAddressesLoadingCache.get(machineName);
} catch (ExecutionException e) {
logger.error("Problem in using the ipAddressCache", e.getCause());
throw Throwables.propagate(e);
}
}
public static boolean isIpv4(String s) {
String IP_V4_ADDRESS_PATTERN = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
Pattern pattern = Pattern.compile(IP_V4_ADDRESS_PATTERN);
Matcher matcher = pattern.matcher(s);
return matcher.matches();
}
}

View File

@ -0,0 +1,339 @@
/**
* 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.util;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
import java.net.URI;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.location.Provider;
import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.virtualbox.domain.BridgedIf;
import org.jclouds.virtualbox.domain.NetworkAdapter;
import org.jclouds.virtualbox.domain.NetworkInterfaceCard;
import org.jclouds.virtualbox.domain.NetworkSpec;
import org.jclouds.virtualbox.functions.IpAddressesLoadingCache;
import org.jclouds.virtualbox.functions.RetrieveActiveBridgedInterfaces;
import org.jclouds.virtualbox.statements.EnableNetworkInterface;
import org.jclouds.virtualbox.statements.GetIPAddressFromMAC;
import org.jclouds.virtualbox.statements.ScanNetworkWithPing;
import org.virtualbox_4_1.HostNetworkInterfaceType;
import org.virtualbox_4_1.IDHCPServer;
import org.virtualbox_4_1.IHostNetworkInterface;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.INetworkAdapter;
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.LockType;
import org.virtualbox_4_1.NetworkAttachmentType;
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.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.Uninterruptibles;
import com.google.inject.Inject;
/**
* Utilities to manage VirtualBox networks on guests
*
* @author Andrea Turli
*/
@Singleton
public class NetworkUtils {
// TODO parameterize
public static final int MASTER_PORT = 2222;
private static final String VIRTUALBOX_HOST_GATEWAY = "10.0.2.15";
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final Supplier<VirtualBoxManager> manager;
private final MachineUtils machineUtils;
private final Supplier<NodeMetadata> host;
private final Supplier<URI> providerSupplier;
private final IpAddressesLoadingCache ipAddressesLoadingCache;
private final RunScriptOnNode.Factory scriptRunnerFactory;
private final Supplier<NodeMetadata> hostSupplier;
@Inject
public NetworkUtils(Supplier<VirtualBoxManager> manager, MachineUtils machineUtils,
MachineController machineController,
Supplier<NodeMetadata> host,
@Provider Supplier<URI> providerSupplier,
IpAddressesLoadingCache ipAddressesLoadingCache,
Supplier<NodeMetadata> hostSupplier,
RunScriptOnNode.Factory scriptRunnerFactory) {
this.manager = manager;
this.machineUtils = machineUtils;
this.host = checkNotNull(host, "host");
this.providerSupplier = checkNotNull(providerSupplier,
"endpoint to virtualbox websrvd is needed");
this.ipAddressesLoadingCache = ipAddressesLoadingCache;
this.scriptRunnerFactory = scriptRunnerFactory;
this.hostSupplier = hostSupplier;
}
public NetworkSpec createNetworkSpecWhenVboxIsLocalhost() {
NetworkAdapter natAdapter = NetworkAdapter.builder()
.networkAttachmentType(NetworkAttachmentType.NAT)
.build();
NetworkInterfaceCard natIfaceCard = NetworkInterfaceCard.builder()
.addNetworkAdapter(natAdapter)
.slot(1L)
.build();
NetworkAdapter hostOnlyAdapter = NetworkAdapter.builder()
.networkAttachmentType(NetworkAttachmentType.HostOnly)
.build();
// create new hostOnly interface if needed, otherwise use the one already there with dhcp enabled ...
String hostOnlyIfName = getHostOnlyIfOrCreate();
NetworkInterfaceCard hostOnlyIfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(hostOnlyAdapter)
.addHostInterfaceName(hostOnlyIfName).slot(0L).build();
return createNetworkSpecForHostOnlyNATNICs(natIfaceCard, hostOnlyIfaceCard);
}
public boolean enableNetworkInterface(NodeMetadata nodeMetadata, NetworkInterfaceCard networkInterfaceCard) {
ExecResponse execResponse = null;
try {
execResponse = machineUtils.runScriptOnNode(nodeMetadata,
new EnableNetworkInterface(networkInterfaceCard), RunScriptOptions.NONE).get();
} catch (InterruptedException e) {
logger.error(e.getMessage());
} catch (ExecutionException e) {
logger.error(e.getMessage());
}
if(execResponse == null)
return false;
return execResponse.getExitStatus() == 0;
}
private NetworkSpec createNetworkSpecForHostOnlyNATNICs(NetworkInterfaceCard natIfaceCard,
NetworkInterfaceCard hostOnlyIfaceCard) {
return NetworkSpec.builder()
.addNIC(hostOnlyIfaceCard)
.addNIC(natIfaceCard)
.build();
}
public String getHostOnlyIfOrCreate() {
IHostNetworkInterface availableHostInterfaceIf = returnExistingHostNetworkInterfaceWithDHCPenabledOrNull(manager
.get().getVBox().getHost().getNetworkInterfaces());
if (availableHostInterfaceIf==null) {
final String hostOnlyIfName = createHostOnlyIf();
assignDHCPtoHostOnlyInterface(hostOnlyIfName);
return hostOnlyIfName;
} else {
return availableHostInterfaceIf.getName();
}
}
private void assignDHCPtoHostOnlyInterface(final String hostOnlyIfName) {
List<IHostNetworkInterface> availableNetworkInterfaces = manager.get().getVBox().getHost()
.getNetworkInterfaces();
IHostNetworkInterface iHostNetworkInterfaceWithHostOnlyIfName = Iterables.getOnlyElement(Iterables.filter(availableNetworkInterfaces, new Predicate<IHostNetworkInterface>() {
@Override
public boolean apply(IHostNetworkInterface iHostNetworkInterface) {
return iHostNetworkInterface.getName().equals(hostOnlyIfName);
}
}));
String hostOnlyIfIpAddress = iHostNetworkInterfaceWithHostOnlyIfName.getIPAddress();
String dhcpIpAddress = hostOnlyIfIpAddress.substring(0, hostOnlyIfIpAddress.lastIndexOf(".")) + ".254";
String dhcpNetmask = "255.255.255.0";
String dhcpLowerIp = hostOnlyIfIpAddress.substring(0, hostOnlyIfIpAddress.lastIndexOf(".")) + ".2";
String dhcpUpperIp = hostOnlyIfIpAddress.substring(0, hostOnlyIfIpAddress.lastIndexOf(".")) + ".253";
NodeMetadata hostNodeMetadata = getHostNodeMetadata();
ExecResponse response = scriptRunnerFactory
.create(hostNodeMetadata,
Statements.exec(String
.format("VBoxManage dhcpserver add --ifname %s --ip %s --netmask %s --lowerip %s --upperip %s --enable",
hostOnlyIfName, dhcpIpAddress, dhcpNetmask, dhcpLowerIp, dhcpUpperIp)), runAsRoot(false).wrapInInitScript(false)).init().call();
checkState(response.getExitStatus()==0);
}
private String createHostOnlyIf() {
final String hostOnlyIfName;
NodeMetadata hostNodeMetadata = getHostNodeMetadata();
ExecResponse createHostOnlyResponse = scriptRunnerFactory
.create(hostNodeMetadata, Statements.exec("VBoxManage hostonlyif create"),
runAsRoot(false).wrapInInitScript(false)).init().call();
String output = createHostOnlyResponse.getOutput();
checkState(createHostOnlyResponse.getExitStatus()==0);
checkState(output.contains("'"), "cannot create hostonlyif");
hostOnlyIfName = output.substring(output.indexOf("'") + 1, output.lastIndexOf("'"));
return hostOnlyIfName;
}
private NodeMetadata getHostNodeMetadata() {
NodeMetadata hostNodeMetadata = NodeMetadataBuilder
.fromNodeMetadata(host.get())
.publicAddresses(
ImmutableList.of(providerSupplier.get().getHost()))
.build();
return hostNodeMetadata;
}
private IHostNetworkInterface returnExistingHostNetworkInterfaceWithDHCPenabledOrNull(Iterable<IHostNetworkInterface> availableNetworkInterfaces) {
checkNotNull(availableNetworkInterfaces);
return Iterables.getFirst(filterAvailableNetworkInterfaceByHostOnlyAndDHCPenabled(availableNetworkInterfaces), null);
}
/**
* @param availableNetworkInterfaces
* @param hostOnlyIfIpAddress
* @return
*/
private Iterable<IHostNetworkInterface> filterAvailableNetworkInterfaceByHostOnlyAndDHCPenabled(Iterable<IHostNetworkInterface> availableNetworkInterfaces) {
Iterable<IHostNetworkInterface> filteredNetworkInterfaces = Iterables.filter(availableNetworkInterfaces, new Predicate<IHostNetworkInterface>() {
@Override
public boolean apply(IHostNetworkInterface iHostNetworkInterface) {
// this is an horrible workaround cause iHostNetworkInterface.getDhcpEnabled is working only for windows host
boolean match = false;
List<IDHCPServer> availableDHCPservers = manager.get().getVBox().getDHCPServers();
for (IDHCPServer idhcpServer : availableDHCPservers) {
if(idhcpServer.getEnabled() && idhcpServer.getNetworkName().equals(iHostNetworkInterface.getNetworkName()))
match = true;
}
return iHostNetworkInterface.getInterfaceType().equals(HostNetworkInterfaceType.HostOnly) &&
match;
}
});
return filteredNetworkInterfaces;
}
public String getIpAddressFromNicSlot(String machineNameOrId, long nicSlot) {
MachineNameOrIdAndNicSlot machineNameOrIdAndNicSlot =
MachineNameOrIdAndNicSlot.fromParts(machineNameOrId, nicSlot);
logger.debug("Looking for an available IP address for %s at slot %s ...",
machineNameOrIdAndNicSlot.getMachineNameOrId(),
machineNameOrIdAndNicSlot.getSlotText());
try {
String ipAddress = ipAddressesLoadingCache.get(machineNameOrIdAndNicSlot);
while(!isValidIpForHostOnly(machineNameOrIdAndNicSlot, ipAddress)) {
ipAddressesLoadingCache.invalidate(machineNameOrIdAndNicSlot);
ipAddress = ipAddressesLoadingCache.get(machineNameOrIdAndNicSlot);
}
logger.debug("Found an available IP address %s for guest: %s at slot: %s",
ipAddress,
machineNameOrIdAndNicSlot.getMachineNameOrId(),
machineNameOrIdAndNicSlot.getSlotText());
return ipAddress;
} catch (ExecutionException e) {
logger.error("Problem in using the ipAddressCache", e.getCause());
throw Throwables.propagate(e);
}
}
public static boolean isIpv4(String s) {
String IP_V4_ADDRESS_PATTERN = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
Pattern pattern = Pattern.compile(IP_V4_ADDRESS_PATTERN);
Matcher matcher = pattern.matcher(s);
return matcher.matches();
}
public boolean isValidIpForHostOnly(MachineNameOrIdAndNicSlot machineNameOrIdAndNicSlot, String ip) {
final String vmNameOrId = machineNameOrIdAndNicSlot.getMachineNameOrId();
IMachine machine = manager.get().getVBox().findMachine(vmNameOrId);
long slot = machineNameOrIdAndNicSlot.getSlot();
if(ip.equals(VIRTUALBOX_HOST_GATEWAY) || !isValidHostOnlyIpAddress(ip, slot, machine)) {
// restart vm
logger.debug("reset node (%s) to refresh guest properties.", vmNameOrId);
machineUtils.lockSessionOnMachineAndApply(vmNameOrId, LockType.Shared,
new Function<ISession, Void>() {
@Override
public Void apply(ISession session) {
session.getConsole().reset();
long time = 15;
logger.debug("Waiting %s secs for the reset of (%s) ...", time, vmNameOrId);
Uninterruptibles.sleepUninterruptibly(time, TimeUnit.SECONDS);
return null;
}
});
return false;
}
return true;
}
public static boolean isValidHostOnlyIpAddress(String ip, long slot,
IMachine machine) {
boolean result = isIpv4(ip) && machine.getNetworkAdapter(slot).getAttachmentType().equals(NetworkAttachmentType.HostOnly)
&& !ipBelongsToNatRange(ip);
return result;
}
private static boolean ipBelongsToNatRange(String ip) {
return ip.startsWith("10.0.3");
}
protected String getIpAddressFromBridgedNIC(INetworkAdapter networkAdapter,
String network) {
// RetrieveActiveBridgedInterfaces
List<BridgedIf> activeBridgedInterfaces = new RetrieveActiveBridgedInterfaces(scriptRunnerFactory).apply(hostSupplier.get());
BridgedIf activeBridgedIf = checkNotNull(Iterables.get(activeBridgedInterfaces, 0), "activeBridgedInterfaces");
network = activeBridgedIf.getIpAddress();
// scan ip
RunScriptOnNode ipScanRunScript = scriptRunnerFactory.create(
hostSupplier.get(), new ScanNetworkWithPing(network),
RunScriptOptions.NONE);
ExecResponse execResponse = ipScanRunScript.init().call();
checkState(execResponse.getExitStatus() == 0);
// retrieve ip from mac
RunScriptOnNode getIpFromMACAddressRunScript = scriptRunnerFactory
.create(hostSupplier.get(), new GetIPAddressFromMAC(
networkAdapter.getMACAddress()),
RunScriptOptions.NONE);
ExecResponse ipExecResponse = getIpFromMACAddressRunScript.init()
.call();
checkState(ipExecResponse.getExitStatus() == 0);
return checkNotNull(ipExecResponse.getOutput(), "ipAddress");
}
}

View File

@ -1,4 +1,139 @@
images:
- id: ubuntu-10.04.4-server-i386
name: ubuntu-10.04-server-i386
description: ubuntu 10.04.4 server (i386)
os_arch: x86
os_family: ubuntu
os_description: ubuntu
os_version: 10.04.4
iso: http://releases.ubuntu.com/10.04.4/ubuntu-10.04.4-server-i386.iso
iso_md5: fc08a01e78348e3918180ea91a6883bb
username: toor
credential: password
keystroke_sequence: |
<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
fb=false debconf/frontend=noninteractive
console-setup/ask_detect=false console-setup/modelcode=pc105 console-setup/layoutcode=us
initrd=/install/initrd.gz -- <Enter>
preseed_cfg: |
## Options to set on the command line
d-i debian-installer/locale string en_US
d-i console-setup/ask_detect boolean false
d-i console-setup/layoutcode string us
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
d-i time/zone string UTC
d-i clock-setup/utc-auto boolean true
d-i clock-setup/utc boolean true
d-i kbd-chooser/method select American English
d-i netcfg/wireless_wep string
d-i base-installer/kernel/override-image string linux-server
d-i debconf debconf/frontend select Noninteractive
d-i pkgsel/install-language-support boolean false
tasksel tasksel/first multiselect standard, ubuntu-server
d-i partman-auto/method string lvm
#d-i partman-auto/purge_lvm_from_device boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-auto/choose_recipe select atomic
d-i partman/confirm_write_new_label boolean true
d-i partman/confirm_nooverwrite boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
# Write the changes to disks and configure LVM?
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-auto-lvm/guided_size string max
## Default user, we can get away with a recipe to change this
d-i passwd/user-fullname string toor
d-i passwd/username string toor
d-i passwd/user-password password password
d-i passwd/user-password-again password password
d-i user-setup/encrypt-home boolean false
d-i user-setup/allow-password-weak boolean true
d-i pkgsel/include string openssh-server ntp
# Whether to upgrade packages after debootstrap.
# Allowed values: none, safe-upgrade, full-upgrade
d-i pkgsel/upgrade select full-upgrade
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean true
d-i finish-install/reboot_in_progress note
#For the update
d-i pkgsel/update-policy select none
# debconf-get-selections --install
#Use mirror
choose-mirror-bin mirror/http/proxy string
- id: ubuntu-10.04.4-server-amd64
name: ubuntu-10.04-server-amd64
description: ubuntu 10.04.4 server (amd64)
os_arch: amd64
os_family: ubuntu
os_description: ubuntu
os_version: 10.04.4
os_64bit: true
iso: http://releases.ubuntu.com/10.04.4/ubuntu-10.04.4-server-amd64.iso
iso_md5: 9b218654cdcdf9722171648c52f8a088
username: toor
credential: password
keystroke_sequence: |
<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
fb=false debconf/frontend=noninteractive
console-setup/ask_detect=false console-setup/modelcode=pc105 console-setup/layoutcode=us
initrd=/install/initrd.gz -- <Enter>
preseed_cfg: |
## Options to set on the command line
d-i debian-installer/locale string en_US
d-i console-setup/ask_detect boolean false
d-i console-setup/layoutcode string us
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
d-i time/zone string UTC
d-i clock-setup/utc-auto boolean true
d-i clock-setup/utc boolean true
d-i kbd-chooser/method select American English
d-i netcfg/wireless_wep string
d-i base-installer/kernel/override-image string linux-server
d-i debconf debconf/frontend select Noninteractive
d-i pkgsel/install-language-support boolean false
tasksel tasksel/first multiselect standard, ubuntu-server
d-i partman-auto/method string lvm
#d-i partman-auto/purge_lvm_from_device boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-auto/choose_recipe select atomic
d-i partman/confirm_write_new_label boolean true
d-i partman/confirm_nooverwrite boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
# Write the changes to disks and configure LVM?
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-auto-lvm/guided_size string max
## Default user, we can get away with a recipe to change this
d-i passwd/user-fullname string toor
d-i passwd/username string toor
d-i passwd/user-password password password
d-i passwd/user-password-again password password
d-i user-setup/encrypt-home boolean false
d-i user-setup/allow-password-weak boolean true
d-i pkgsel/include string openssh-server ntp
# Whether to upgrade packages after debootstrap.
# Allowed values: none, safe-upgrade, full-upgrade
d-i pkgsel/upgrade select full-upgrade
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean true
d-i finish-install/reboot_in_progress note
#For the update
d-i pkgsel/update-policy select none
# debconf-get-selections --install
#Use mirror
choose-mirror-bin mirror/http/proxy string
- id: ubuntu-11.04-i386
name: ubuntu-11.04-server-i386
description: ubuntu 11.04 server (i386)
@ -27,7 +162,7 @@ images:
d-i time/zone string UTC
d-i clock-setup/utc-auto boolean true
d-i clock-setup/utc boolean true
d-i kbd-chooser/method select American English
d-i kbd-chooser/method select American English
d-i netcfg/wireless_wep string
d-i base-installer/kernel/override-image string linux-server
# Choices: Dialog, Readline, Gnome, Kde, Editor, Noninteractive
@ -142,8 +277,9 @@ images:
os_version: 12.04.1
os_64bit: true
iso: http://releases.ubuntu.com/12.04/ubuntu-12.04.1-server-amd64.iso
iso_md5: a8c667e871f48f3a662f3fbf1c3ddb17
username: toor
credential: $user
credential: password
keystroke_sequence: |
<Esc><Esc><Enter>
/install/vmlinuz noapic preseed/url=http://10.0.2.2:8080/src/test/resources/preseed.cfg

View File

@ -25,6 +25,7 @@ import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTA
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
@ -53,6 +54,7 @@ import org.jclouds.virtualbox.functions.IMachineToVmSpec;
import org.jclouds.virtualbox.functions.admin.UnregisterMachineIfExistsAndDeleteItsMedia;
import org.jclouds.virtualbox.util.MachineController;
import org.jclouds.virtualbox.util.MachineUtils;
import org.jclouds.virtualbox.util.NetworkUtils;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeClass;
@ -71,6 +73,7 @@ import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.Uninterruptibles;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
@ -103,6 +106,9 @@ public class BaseVirtualBoxClientLiveTest extends BaseComputeServiceContextLiveT
@Inject
protected MachineUtils machineUtils;
@Inject
protected NetworkUtils networkUtils;
protected String hostVersion;
protected String operatingSystemIso;
@ -155,10 +161,7 @@ public class BaseVirtualBoxClientLiveTest extends BaseComputeServiceContextLiveT
int attempts = 0;
while (attempts < 10 && !vm.getSessionState().equals(SessionState.Unlocked)) {
attempts++;
try {
Thread.sleep(200l);
} catch (InterruptedException e) {
}
Uninterruptibles.sleepUninterruptibly(200, TimeUnit.MILLISECONDS);
}
machineUtils.applyForMachine(vmNameOrId, new UnregisterMachineIfExistsAndDeleteItsMedia(vmSpec));

View File

@ -36,6 +36,7 @@ import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.scriptbuilder.statements.login.AdminAccess;
import org.jclouds.ssh.SshClient;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest;
@ -50,7 +51,7 @@ import com.google.inject.Module;
*
* @author Adrian Cole
*/
@Test(groups = "live", singleThreaded = true, testName = "VirtualBoxExperimentLiveTest")
@Test(groups = "live", testName = "VirtualBoxExperimentLiveTest")
public class VirtualBoxExperimentLiveTest extends BaseVirtualBoxClientLiveTest {
@Resource
@ -71,7 +72,7 @@ public class VirtualBoxExperimentLiveTest extends BaseVirtualBoxClientLiveTest {
int numNodes = 3;
final String clusterName = "test-launch-cluster";
Set<? extends NodeMetadata> nodes = context.getComputeService().createNodesInGroup(clusterName, numNodes,
TemplateOptions.Builder.overrideLoginUser("toor")); //TODO runScript(AdminAccess.standard()));
TemplateOptions.Builder.overrideLoginUser("toor").runScript(AdminAccess.standard()));
assertEquals(numNodes, nodes.size(), "wrong number of nodes");
for (NodeMetadata node : nodes) {
assertTrue(node.getGroup().equals("test-launch-cluster"));

View File

@ -30,7 +30,7 @@ import static org.testng.Assert.assertEquals;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.virtualbox.config.VirtualBoxComputeServiceContextModule;
import org.jclouds.virtualbox.util.MachineUtils;
import org.jclouds.virtualbox.util.NetworkUtils;
import org.testng.annotations.Test;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.INATEngine;
@ -64,18 +64,18 @@ public class IMachineToNodeMetadataTest {
expect(natEng.getRedirects()).andReturn(ImmutableList.of("0,1,127.0.0.1,2222,,22"));
INetworkAdapter hostOnly = createNiceMock(INetworkAdapter.class);
MachineUtils machineUtils = createNiceMock(MachineUtils.class);
NetworkUtils networkUtils = createNiceMock(NetworkUtils.class);
replay(vm, nat, natEng, hostOnly, machineUtils);
replay(vm, nat, natEng, hostOnly, networkUtils);
NodeMetadata node = new IMachineToNodeMetadata(VirtualBoxComputeServiceContextModule.toPortableNodeStatus,
machineUtils).apply(vm);
networkUtils).apply(vm);
assertEquals(MASTER_NAME, node.getName());
assertEquals(1, 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(NetworkUtils.MASTER_PORT, node.getLoginPort());
assertEquals("", node.getGroup());
}
@ -103,12 +103,12 @@ public class IMachineToNodeMetadataTest {
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"));
MachineUtils machineUtils = createNiceMock(MachineUtils.class);
NetworkUtils networkUtils = createNiceMock(NetworkUtils.class);
replay(vm, nat, natEng, hostOnly, machineUtils);
replay(vm, nat, natEng, hostOnly, networkUtils);
NodeMetadata node = new IMachineToNodeMetadata(VirtualBoxComputeServiceContextModule.toPortableNodeStatus,
machineUtils).apply(vm);
networkUtils).apply(vm);
assertEquals(name, node.getName());
assertEquals(group, node.getGroup());

View File

@ -41,11 +41,11 @@ import com.google.common.collect.Iterables;
public class ImageFromYamlStringTest {
public static final Image TEST1 = new ImageBuilder()
.id("ubuntu-11.04-i386")
.name("ubuntu-11.04-server-i386")
.description("ubuntu 11.04 server (i386)")
.id("ubuntu-10.04.4-server-i386")
.name("ubuntu-10.04-server-i386")
.description("ubuntu")
.operatingSystem(
OperatingSystem.builder().description("ubuntu").family(OsFamily.UBUNTU).version("11.04")
OperatingSystem.builder().description("ubuntu").family(OsFamily.UBUNTU).version("10.04.4")
.arch("x86").build())
.status(Image.Status.AVAILABLE).build();

View File

@ -39,8 +39,7 @@ import org.jclouds.virtualbox.domain.VmSpec;
import org.jclouds.virtualbox.functions.CloneAndRegisterMachineFromIMachineIfNotAlreadyExists;
import org.jclouds.virtualbox.functions.CreateAndInstallVm;
import org.jclouds.virtualbox.functions.IMachineToSshClient;
import org.jclouds.virtualbox.functions.IpAddressesLoadingCache;
import org.jclouds.virtualbox.util.MachineUtils;
import org.jclouds.virtualbox.util.NetworkUtils;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.virtualbox_4_1.CleanupMode;
@ -57,7 +56,7 @@ import com.google.inject.Injector;
/**
* @author Andrea Turli
*/
@Test(groups = "live", singleThreaded = true, testName = "GuestAdditionsInstallerLiveTest")
@Test(groups = "live", singleThreaded = true, testName = "GuestAdditionsInstallerLiveTest", enabled=false)
public class GuestAdditionsInstallerLiveTest extends BaseVirtualBoxClientLiveTest {
private Injector injector;
@ -65,7 +64,6 @@ public class GuestAdditionsInstallerLiveTest extends BaseVirtualBoxClientLiveTes
private Predicate<SshClient> sshResponds;
private MasterSpec machineSpec;
private IpAddressesLoadingCache ipAddressesLoadingCache;
@Override
@BeforeClass(groups = "live")
@ -117,9 +115,8 @@ public class GuestAdditionsInstallerLiveTest extends BaseVirtualBoxClientLiveTes
sshResponds = injector.getInstance(SshResponds.class);
checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh",
machine.getName());
ipAddressesLoadingCache = injector.getInstance(IpAddressesLoadingCache.class);
assertTrue(MachineUtils.isIpv4(ipAddressesLoadingCache.apply(machine.getName())));
assertTrue(NetworkUtils.isIpv4(networkUtils.getIpAddressFromNicSlot(machine.getName(), 0l)));
} finally {
for (String vmNameOrId : ImmutableSet.of(machine.getName())) {

View File

@ -45,13 +45,7 @@ public class InstallGuestAdditionsLiveTest extends BaseVirtualBoxClientLiveTest
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"
+ "service vboxadd setup\n"
+ "VBoxService\n"
+ "echo VBoxService > /etc/rc.local\n"
+ "echo exit 0 >> /etc/rc.local\n"
+ "umount /mnt\n"
, scripts);
+ "/mnt/VBoxLinuxAdditions.run --nox11\n", scripts);
}
public void testIsoNotPresent() {
@ -67,12 +61,7 @@ public class InstallGuestAdditionsLiveTest extends BaseVirtualBoxClientLiveTest
+ "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"
+ "service vboxadd setup\n"
+ "VBoxService\n"
+ "echo VBoxService > /etc/rc.local\n"
+ "echo exit 0 >> /etc/rc.local\n"
+ "umount /mnt\n", scripts);
+ "/mnt/VBoxLinuxAdditions.run --nox11\n", scripts);
}
}

View File

@ -18,9 +18,11 @@
*/
package org.jclouds.virtualbox.util;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
import static org.testng.AssertJUnit.assertTrue;
import org.jclouds.config.ValueOfConfigurationKeyOrNull;
import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest;
@ -35,20 +37,17 @@ import org.jclouds.virtualbox.domain.StorageController;
import org.jclouds.virtualbox.domain.VmSpec;
import org.jclouds.virtualbox.functions.CloneAndRegisterMachineFromIMachineIfNotAlreadyExists;
import org.jclouds.virtualbox.functions.CreateAndInstallVm;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
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.SessionState;
import org.virtualbox_4_1.StorageBus;
import com.google.common.base.CaseFormat;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Injector;
@Test(groups = "live", testName = "MachineControllerLiveTest")
@ -62,62 +61,134 @@ public class MachineUtilsLiveTest extends BaseVirtualBoxClientLiveTest {
public void setupContext() {
super.setupContext();
instanceName = VIRTUALBOX_IMAGE_PREFIX
+ CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName());
+ CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName());
StorageController ideController = StorageController
.builder()
.name("IDE Controller")
.bus(StorageBus.IDE)
.attachISO(0, 0, operatingSystemIso)
.attachHardDisk(
HardDisk.builder().diskpath(adminDisk(instanceName)).controllerPort(0).deviceSlot(1)
.autoDelete(true).build()).attachISO(1, 1, guestAdditionsIso).build();
.builder()
.name("IDE Controller")
.bus(StorageBus.IDE)
.attachISO(0, 0, operatingSystemIso)
.attachHardDisk(
HardDisk.builder().diskpath(adminDisk(instanceName)).controllerPort(0).deviceSlot(1).autoDelete(true)
.build()).attachISO(1, 1, guestAdditionsIso).build();
VmSpec instanceVmSpec = VmSpec.builder().id(instanceName).name(instanceName).osTypeId("").memoryMB(512)
.cleanUpMode(CleanupMode.Full).controller(ideController).forceOverwrite(true).build();
.cleanUpMode(CleanupMode.Full).controller(ideController).forceOverwrite(true).build();
Injector injector = view.utils().injector();
Function<String, String> configProperties = injector.getInstance(ValueOfConfigurationKeyOrNull.class);
IsoSpec isoSpec = IsoSpec
.builder()
.sourcePath(operatingSystemIso)
.installationScript(
configProperties.apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE).replace("HOSTNAME",
instanceVmSpec.getVmName())).build();
.builder()
.sourcePath(operatingSystemIso)
.installationScript(
configProperties.apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE).replace("HOSTNAME",
instanceVmSpec.getVmName())).build();
NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
.tcpRedirectRule("127.0.0.1", 2222, "", 22).build();
.tcpRedirectRule("127.0.0.1", 2222, "", 22).build();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
.build();
.build();
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
machineSpec = MasterSpec.builder().iso(isoSpec).vm(instanceVmSpec).network(networkSpec).build();
}
@Test
public void lockSessionOnMachine() {
IMachine machine = cloneFromMaster();
ISession session = machineUtils.lockSessionOnMachineAndApply(instanceName, LockType.Shared,
new Function<ISession, ISession>() {
@Test(description = "write lock is acquired and released correctly")
public void writeLockSessionOnMachine() {
final IMachine clone = cloneFromMaster();
ISession session = machineUtils.writeLockMachineAndApplyToSession(clone.getName(),
new Function<ISession, ISession>() {
@Override
public ISession apply(ISession session) {
assertTrue(session.getMachine().getName().equals(clone.getName()));
return session;
}
});
checkState(session.getState().equals(SessionState.Unlocked));
undoVm(clone.getName());
}
@Test(dependsOnMethods="writeLockSessionOnMachine", description = "shared lock is acquired and released correctly")
public void sharedLockSessionOnMachine() {
final IMachine clone = cloneFromMaster();
ISession session = machineUtils.sharedLockMachineAndApplyToSession(clone.getName(),
new Function<ISession, ISession>() {
@Override
public ISession apply(ISession session) {
assertTrue(session.getMachine().getName().equals(clone.getName()));
return session;
}
});
checkState(session.getState().equals(SessionState.Unlocked));
undoVm(clone.getName());
}
@Test(dependsOnMethods="sharedLockSessionOnMachine", description = "shared lock can be acquired after a write lock")
public void sharedLockCanBeAcquiredAfterWriteLockSessionOnMachine() {
final IMachine clone = cloneFromMaster();
try {
ISession writeSession = machineUtils.writeLockMachineAndApplyToSession(clone.getName(),
new Function<ISession, ISession>() {
@Override
public ISession apply(ISession session) {
return session;
public ISession apply(ISession writeSession) {
checkState(writeSession.getState().equals(SessionState.Locked));
//ISession sharedSession = sharedSession(clone);
return writeSession;
}
});
checkState(session.getState().equals(SessionState.Unlocked));
machine = manager.get().getVBox().findMachine(instanceName);
undoVm(instanceName);
checkState(writeSession.getState().equals(SessionState.Unlocked));
} finally {
undoVm(clone.getName());
}
}
private ISession sharedSession(final IMachine clone) {
ISession sharedSession = machineUtils.sharedLockMachineAndApplyToSession(clone.getName(),
new Function<ISession, ISession>() {
@Override
public ISession apply(ISession sharedSession) {
checkState(sharedSession.getState().equals(SessionState.Locked));
assertTrue(sharedSession.getMachine().getName().equals(clone.getName()));
return sharedSession;
}
});
return sharedSession;
}
@Test(dependsOnMethods="sharedLockCanBeAcquiredAfterWriteLockSessionOnMachine", description = "write lock cannot be acquired after a shared lock")
public void writeLockCannotBeAcquiredAfterSharedLockSessionOnMachine() {
final IMachine clone = cloneFromMaster();
try {
ISession sharedSession = machineUtils.sharedLockMachineAndApplyToSession(clone.getName(),
new Function<ISession, ISession>() {
@Override
public ISession apply(ISession sharedSession) {
checkState(sharedSession.getState().equals(SessionState.Locked));
return sharedSession;
}
});
checkState(sharedSession.getState().equals(SessionState.Unlocked));
ISession writeSession = machineUtils.writeLockMachineAndApplyToSession(clone.getName(),
new Function<ISession, ISession>() {
@Override
public ISession apply(ISession writeSession) {
checkState(writeSession.getState().equals(SessionState.Locked));
assertTrue(writeSession.getMachine().getName().equals(clone.getName()));
return writeSession;
}
});
checkState(writeSession.getState().equals(SessionState.Unlocked));
} finally {
undoVm(clone.getName());
}
}
private IMachine cloneFromMaster() {
IMachine source = getVmWithGuestAdditionsInstalled();
CloneSpec cloneSpec = CloneSpec.builder().vm(machineSpec.getVmSpec()).network(machineSpec.getNetworkSpec())
.master(source).linked(true).build();
.master(source).linked(true).build();
return new CloneAndRegisterMachineFromIMachineIfNotAlreadyExists(manager, workingDir, machineUtils)
.apply(cloneSpec);
.apply(cloneSpec);
}
private IMachine getVmWithGuestAdditionsInstalled() {
@ -130,13 +201,4 @@ public class MachineUtilsLiveTest extends BaseVirtualBoxClientLiveTest {
return manager.get().getVBox().findMachine(masterSpecForTest.getVmSpec().getVmId());
}
}
@Override
@AfterClass(groups = "live")
protected void tearDown() throws Exception {
for (String vmName : ImmutableSet.of(instanceName)) {
undoVm(vmName);
}
super.tearDown();
}
}

View File

@ -1,4 +1,139 @@
images:
- id: ubuntu-10.04.4-server-i386
name: ubuntu-10.04-server-i386
description: ubuntu 10.04.4 server (i386)
os_arch: x86
os_family: ubuntu
os_description: ubuntu
os_version: 10.04.4
iso: http://releases.ubuntu.com/10.04.4/ubuntu-10.04.4-server-i386.iso
iso_md5: fc08a01e78348e3918180ea91a6883bb
username: toor
credential: password
keystroke_sequence: |
<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
fb=false debconf/frontend=noninteractive
console-setup/ask_detect=false console-setup/modelcode=pc105 console-setup/layoutcode=us
initrd=/install/initrd.gz -- <Enter>
preseed_cfg: |
## Options to set on the command line
d-i debian-installer/locale string en_US
d-i console-setup/ask_detect boolean false
d-i console-setup/layoutcode string us
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
d-i time/zone string UTC
d-i clock-setup/utc-auto boolean true
d-i clock-setup/utc boolean true
d-i kbd-chooser/method select American English
d-i netcfg/wireless_wep string
d-i base-installer/kernel/override-image string linux-server
d-i debconf debconf/frontend select Noninteractive
d-i pkgsel/install-language-support boolean false
tasksel tasksel/first multiselect standard, ubuntu-server
d-i partman-auto/method string lvm
#d-i partman-auto/purge_lvm_from_device boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-auto/choose_recipe select atomic
d-i partman/confirm_write_new_label boolean true
d-i partman/confirm_nooverwrite boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
# Write the changes to disks and configure LVM?
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-auto-lvm/guided_size string max
## Default user, we can get away with a recipe to change this
d-i passwd/user-fullname string toor
d-i passwd/username string toor
d-i passwd/user-password password password
d-i passwd/user-password-again password password
d-i user-setup/encrypt-home boolean false
d-i user-setup/allow-password-weak boolean true
d-i pkgsel/include string openssh-server ntp
# Whether to upgrade packages after debootstrap.
# Allowed values: none, safe-upgrade, full-upgrade
d-i pkgsel/upgrade select full-upgrade
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean true
d-i finish-install/reboot_in_progress note
#For the update
d-i pkgsel/update-policy select none
# debconf-get-selections --install
#Use mirror
choose-mirror-bin mirror/http/proxy string
- id: ubuntu-10.04.4-server-amd64
name: ubuntu-10.04-server-amd64
description: ubuntu 10.04.4 server (amd64)
os_arch: amd64
os_family: ubuntu
os_description: ubuntu
os_version: 10.04.4
os_64bit: true
iso: http://releases.ubuntu.com/10.04.4/ubuntu-10.04.4-server-amd64.iso
iso_md5: 9b218654cdcdf9722171648c52f8a088
username: toor
credential: password
keystroke_sequence: |
<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
fb=false debconf/frontend=noninteractive
console-setup/ask_detect=false console-setup/modelcode=pc105 console-setup/layoutcode=us
initrd=/install/initrd.gz -- <Enter>
preseed_cfg: |
## Options to set on the command line
d-i debian-installer/locale string en_US
d-i console-setup/ask_detect boolean false
d-i console-setup/layoutcode string us
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
d-i time/zone string UTC
d-i clock-setup/utc-auto boolean true
d-i clock-setup/utc boolean true
d-i kbd-chooser/method select American English
d-i netcfg/wireless_wep string
d-i base-installer/kernel/override-image string linux-server
d-i debconf debconf/frontend select Noninteractive
d-i pkgsel/install-language-support boolean false
tasksel tasksel/first multiselect standard, ubuntu-server
d-i partman-auto/method string lvm
#d-i partman-auto/purge_lvm_from_device boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-auto/choose_recipe select atomic
d-i partman/confirm_write_new_label boolean true
d-i partman/confirm_nooverwrite boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
# Write the changes to disks and configure LVM?
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-auto-lvm/guided_size string max
## Default user, we can get away with a recipe to change this
d-i passwd/user-fullname string toor
d-i passwd/username string toor
d-i passwd/user-password password password
d-i passwd/user-password-again password password
d-i user-setup/encrypt-home boolean false
d-i user-setup/allow-password-weak boolean true
d-i pkgsel/include string openssh-server ntp
# Whether to upgrade packages after debootstrap.
# Allowed values: none, safe-upgrade, full-upgrade
d-i pkgsel/upgrade select full-upgrade
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean true
d-i finish-install/reboot_in_progress note
#For the update
d-i pkgsel/update-policy select none
# debconf-get-selections --install
#Use mirror
choose-mirror-bin mirror/http/proxy string
- id: ubuntu-11.04-i386
name: ubuntu-11.04-server-i386
description: ubuntu 11.04 server (i386)
@ -27,7 +162,7 @@ images:
d-i time/zone string UTC
d-i clock-setup/utc-auto boolean true
d-i clock-setup/utc boolean true
d-i kbd-chooser/method select American English
d-i kbd-chooser/method select American English
d-i netcfg/wireless_wep string
d-i base-installer/kernel/override-image string linux-server
# Choices: Dialog, Readline, Gnome, Kde, Editor, Noninteractive
@ -143,6 +278,8 @@ images:
os_64bit: true
iso: http://releases.ubuntu.com/12.04/ubuntu-12.04.1-server-amd64.iso
iso_md5: a8c667e871f48f3a662f3fbf1c3ddb17
username: toor
credential: password
keystroke_sequence: |
<Esc><Esc><Enter>
/install/vmlinuz noapic preseed/url=http://10.0.2.2:8080/src/test/resources/preseed.cfg

View File

@ -42,6 +42,11 @@
<level value="DEBUG" />
<appender-ref ref="CONSOLE" />
</root>
<logger name="net.schmizz.sshj">
<level value="ERROR" />
<appender-ref ref="CONSOLE" />
</logger>
<logger name="org.jclouds">
<level value="DEBUG" />