Merge pull request #428 from andreaturli/dev

issue 384: bridged support
This commit is contained in:
Adrian Cole 2012-03-12 23:37:47 -07:00
commit 538c2129a8
15 changed files with 796 additions and 285 deletions

View File

@ -0,0 +1,203 @@
/**
* 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.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Objects;
/**
* Name: en1: Wi-Fi (AirPort) GUID: 00316e65-0000-4000-8000-28cfdaf2917a Dhcp:
* Disabled IPAddress: 192.168.57.1 NetworkMask: 255.255.255.0 IPV6Address:
* IPV6NetworkMaskPrefixLength: 0 HardwareAddress: 28:cf:da:f2:91:7a MediumType:
* Ethernet Status: Up VBoxNetworkName: HostInterfaceNetworking-en1: Wi-Fi
* (AirPort)
*
* @author Andrea Turli
*
*/
public class BridgedIf {
private final String name;
private final String guid;
private final String dhcp;
private final String ipAddress;
private final String networkMask;
private final String ipv6Address;
private final String ipv6NetworkMask;
private final String mediumType;
private final String status;
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String name;
private String guid;
private String dhcp;
private String ipAddress;
private String networkMask;
private String ipv6Address;
private String iv6NetworkMask;
private String mediumType;
private String status;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder guid(String guid) {
this.guid = guid;
return this;
}
public Builder dhcp(String dhcp) {
this.dhcp = dhcp;
return this;
}
public Builder ip(String ipAddress) {
this.ipAddress = ipAddress;
return this;
}
public Builder networkMask(String networkMask) {
this.networkMask = networkMask;
return this;
}
public Builder ipv6(String ipv6Address) {
this.ipv6Address = ipv6Address;
return this;
}
public Builder ipv6networkMask(String iv6NetworkMask) {
this.iv6NetworkMask = iv6NetworkMask;
return this;
}
public Builder mediumType(String mediumType) {
this.mediumType = mediumType;
return this;
}
public Builder status(String status) {
this.status = status;
return this;
}
public BridgedIf build() {
return new BridgedIf(name, guid, dhcp, ipAddress, networkMask,
ipv6Address, iv6NetworkMask, mediumType, status);
}
}
public BridgedIf(String name, String guid, String dhcp, String ipAddress,
String networkMask, String ipv6Address, String iv6NetworkMask,
String mediumType, String status) {
this.name = checkNotNull(name, "bridgedIf name");
this.guid = guid;
this.dhcp = dhcp;
this.ipAddress = checkNotNull(ipAddress, "bridgedIf ipAddress");
this.networkMask = networkMask;
this.ipv6Address = ipv6Address;
this.ipv6NetworkMask = iv6NetworkMask;
this.mediumType = mediumType;
this.status = checkNotNull(status, "bridgedIf status");
}
public String getName() {
return name;
}
public String getGuid() {
return guid;
}
public String getDhcp() {
return dhcp;
}
public String getIpAddress() {
return ipAddress;
}
public String getNetworkMask() {
return networkMask;
}
public String getIpv6Address() {
return ipv6Address;
}
public String getIpv6NetworkMask() {
return ipv6NetworkMask;
}
public String getMediumType() {
return mediumType;
}
public String getStatus() {
return status;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o instanceof VmSpec) {
BridgedIf other = (BridgedIf) o;
return Objects.equal(name, other.name)
&& Objects.equal(guid, other.guid)
&& Objects.equal(dhcp, other.dhcp)
&& Objects.equal(ipAddress, other.ipAddress)
&& Objects.equal(networkMask, other.networkMask)
&& Objects.equal(ipv6Address, other.ipv6Address)
&& Objects.equal(ipv6NetworkMask, other.ipv6NetworkMask)
&& Objects.equal(mediumType, other.mediumType)
&& Objects.equal(status, other.status);
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(name, guid, dhcp, ipAddress, networkMask, ipv6Address, ipv6NetworkMask, mediumType, status);
}
@Override
public String toString() {
return "BridgedIf{" +
"name=" + name +
", dhcp=" + dhcp +
", ipAddress=" + ipAddress +
", networkMask=" + networkMask +
", ipv6Address=" + ipv6Address +
", ipv6NetworkMask=" + ipv6NetworkMask +
", mediumType=" + mediumType +
", status=" + status +
'}';
}
}

View File

@ -117,6 +117,6 @@ public class CloneSpec {
@Override @Override
public String toString() { public String toString() {
return "IMachineSpec{" + "vmSpec= " + vmSpec + ", networkSpec= " + networkSpec + '}'; return "CloneSpec{" + "vmSpec= " + vmSpec + ", networkSpec= " + networkSpec + '}';
} }
} }

View File

@ -0,0 +1,100 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.virtualbox.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.virtualbox.domain.BridgedIf;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
@Singleton
public class BridgedIfStringToBridgedIf implements Function<String, BridgedIf> {
private static final String BRIDGED_IF_STATUS = "Status";
private static final String BRIDGED_IF_MEDIUM_TYPE = "MediumType";
private static final String BRIDGED_IF_NETWORK_MASK = "NetworkMask";
private static final String BRIDGED_IF_IP_ADDRESS = "IPAddress";
private static final String BRIDGED_IF_GUID = "GUID";
private static final String BRIDGED_IF_NAME = "Name";
@Inject
public BridgedIfStringToBridgedIf() {
}
@Override
public BridgedIf apply(String rawBridgedIf) {
checkNotNull(rawBridgedIf, "rawBridgedIf");
String transformedBridgedIf = transformRawBridgedIf(rawBridgedIf);
Map<String, String> bridegedIfMap = Splitter.on("\n")
.omitEmptyStrings().withKeyValueSeparator("=")
.split(transformedBridgedIf);
return BridgedIf
.builder()
.name(getValueFromMap(bridegedIfMap, BRIDGED_IF_NAME))
.guid(getValueFromMap(bridegedIfMap, BRIDGED_IF_GUID))
.ip(getValueFromMap(bridegedIfMap, BRIDGED_IF_IP_ADDRESS))
.networkMask(getValueFromMap(bridegedIfMap, BRIDGED_IF_NETWORK_MASK))
.mediumType(getValueFromMap(bridegedIfMap, BRIDGED_IF_MEDIUM_TYPE))
.status(getValueFromMap(bridegedIfMap, BRIDGED_IF_STATUS))
.build();
}
private String getValueFromMap(Map<String, String> map, String key) {
return map.get(key).trim();
}
/**
* This is an helper to simplify the split step of the raw bridgedIf
* Substitute first ':' with '='
*
* @param rawBridgedIf
* @return
*/
private String transformRawBridgedIf(String rawBridgedIf) {
Iterable<String> transformedLines = Iterables.transform(
Splitter.on("\n").split(rawBridgedIf),
new Function<String, String>() {
@Override
public String apply(String line) {
return line.replaceFirst(":", "=");
}
});
StringBuilder stringBuilder = new StringBuilder();
for (String line : transformedLines) {
stringBuilder.append(line + "\n");
}
return stringBuilder.toString();
}
}

View File

@ -36,18 +36,15 @@ import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import org.jclouds.virtualbox.Preconfiguration; import org.jclouds.virtualbox.Preconfiguration;
import org.jclouds.virtualbox.domain.ExecutionType;
import org.jclouds.virtualbox.domain.IsoSpec; import org.jclouds.virtualbox.domain.IsoSpec;
import org.jclouds.virtualbox.domain.MasterSpec; import org.jclouds.virtualbox.domain.MasterSpec;
import org.jclouds.virtualbox.domain.VmSpec; import org.jclouds.virtualbox.domain.VmSpec;
import org.jclouds.virtualbox.predicates.GuestAdditionsInstaller; import org.jclouds.virtualbox.predicates.GuestAdditionsInstaller;
import org.jclouds.virtualbox.util.MachineController;
import org.jclouds.virtualbox.util.MachineUtils; import org.jclouds.virtualbox.util.MachineUtils;
import org.virtualbox_4_1.IMachine; 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.LockType;
import org.virtualbox_4_1.VirtualBoxManager; import org.virtualbox_4_1.VirtualBoxManager;
import org.virtualbox_4_1.jaxws.MachineState;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@ -61,124 +58,99 @@ import com.google.inject.Inject;
@Singleton @Singleton
public class CreateAndInstallVm implements Function<MasterSpec, IMachine> { public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private final Supplier<VirtualBoxManager> manager; private final Supplier<VirtualBoxManager> manager;
private final CreateAndRegisterMachineFromIsoIfNotAlreadyExists createAndRegisterMachineFromIsoIfNotAlreadyExists; private final CreateAndRegisterMachineFromIsoIfNotAlreadyExists createAndRegisterMachineFromIsoIfNotAlreadyExists;
private final GuestAdditionsInstaller guestAdditionsInstaller; private final GuestAdditionsInstaller guestAdditionsInstaller;
private final Predicate<SshClient> sshResponds; private final Predicate<SshClient> sshResponds;
private final ExecutionType executionType; private LoadingCache<IsoSpec, URI> preConfiguration;
private LoadingCache<IsoSpec, URI> preConfiguration; private final Function<IMachine, SshClient> sshClientForIMachine;
private final Function<IMachine, SshClient> sshClientForIMachine; private final MachineUtils machineUtils;
private final MachineUtils machineUtils; private final IMachineToNodeMetadata imachineToNodeMetadata;
private final IMachineToNodeMetadata imachineToNodeMetadata; private final MachineController machineController;
@Inject @Inject
public CreateAndInstallVm(Supplier<VirtualBoxManager> manager, public CreateAndInstallVm(
CreateAndRegisterMachineFromIsoIfNotAlreadyExists CreateAndRegisterMachineFromIsoIfNotAlreadyExists, Supplier<VirtualBoxManager> manager,
GuestAdditionsInstaller guestAdditionsInstaller, IMachineToNodeMetadata imachineToNodeMetadata, CreateAndRegisterMachineFromIsoIfNotAlreadyExists CreateAndRegisterMachineFromIsoIfNotAlreadyExists,
Predicate<SshClient> sshResponds, Function<IMachine, SshClient> sshClientForIMachine, GuestAdditionsInstaller guestAdditionsInstaller,
ExecutionType executionType, MachineUtils machineUtils, IMachineToNodeMetadata imachineToNodeMetadata,
@Preconfiguration LoadingCache<IsoSpec, URI> preConfiguration) { Predicate<SshClient> sshResponds,
this.manager = manager; Function<IMachine, SshClient> sshClientForIMachine,
this.createAndRegisterMachineFromIsoIfNotAlreadyExists = CreateAndRegisterMachineFromIsoIfNotAlreadyExists; MachineUtils machineUtils,
this.sshResponds = sshResponds; @Preconfiguration LoadingCache<IsoSpec, URI> preConfiguration, MachineController machineController) {
this.sshClientForIMachine = sshClientForIMachine; this.manager = manager;
this.executionType = executionType; this.createAndRegisterMachineFromIsoIfNotAlreadyExists = CreateAndRegisterMachineFromIsoIfNotAlreadyExists;
this.machineUtils = machineUtils; this.sshResponds = sshResponds;
this.preConfiguration = preConfiguration; this.sshClientForIMachine = sshClientForIMachine;
this.guestAdditionsInstaller = guestAdditionsInstaller; this.machineUtils = machineUtils;
this.imachineToNodeMetadata = imachineToNodeMetadata; this.preConfiguration = preConfiguration;
} this.guestAdditionsInstaller = guestAdditionsInstaller;
this.imachineToNodeMetadata = imachineToNodeMetadata;
this.machineController = machineController;
}
@Override @Override
public IMachine apply(MasterSpec masterSpec) { public IMachine apply(MasterSpec masterSpec) {
VmSpec vmSpec = masterSpec.getVmSpec(); VmSpec vmSpec = masterSpec.getVmSpec();
IsoSpec isoSpec = masterSpec.getIsoSpec(); IsoSpec isoSpec = masterSpec.getIsoSpec();
String vmName = vmSpec.getVmName(); String vmName = vmSpec.getVmName();
IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists.apply(masterSpec); IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists
.apply(masterSpec);
// Launch machine and wait for it to come online // Launch machine and wait for it to come online
ensureMachineIsLaunched(vmName); machineController.ensureMachineIsLaunched(vmName);
URI uri = preConfiguration.getUnchecked(isoSpec); URI uri = preConfiguration.getUnchecked(isoSpec);
String installationKeySequence = isoSpec.getInstallationKeySequence().replace("PRECONFIGURATION_URL", String installationKeySequence = isoSpec.getInstallationKeySequence()
uri.toASCIIString()); .replace("PRECONFIGURATION_URL", uri.toASCIIString());
configureOsInstallationWithKeyboardSequence(vmName, installationKeySequence); configureOsInstallationWithKeyboardSequence(vmName,
SshClient client = sshClientForIMachine.apply(vm); installationKeySequence);
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); logger.debug(">> awaiting installation to finish node(%s)", vmName);
logger.debug(">> awaiting installation of guest additions on vm: %s", vmName); checkState(sshResponds.apply(client),
"timed out waiting for guest %s to be accessible via ssh",
vmName);
checkState(guestAdditionsInstaller.apply(vm)); //logger.debug(">> awaiting installation of guest additions on vm: %s", vmName);
//checkState(guestAdditionsInstaller.apply(vm));
logger.debug(">> awaiting post-installation actions on vm: %s", vmName); logger.debug(">> awaiting post-installation actions on vm: %s", vmName);
NodeMetadata vmMetadata = imachineToNodeMetadata.apply(vm); NodeMetadata vmMetadata = imachineToNodeMetadata.apply(vm);
// TODO for now this is executed on installModuleAssistantIfNeeded as a workaround to some transient execution issue.
// ListenableFuture<ExecResponse> execFuture = machineUtils.runScriptOnNode(vmMetadata, call("cleanupUdevIfNeeded"),
// RunScriptOptions.NONE);
// ExecResponse execResponse = Futures.getUnchecked(execFuture);
// checkState(execResponse.getExitCode() == 0);
logger.debug("<< installation of image complete. Powering down node(%s)", vmName); ListenableFuture<ExecResponse> execFuture =
machineUtils.runScriptOnNode(vmMetadata, call("cleanupUdevIfNeeded"), RunScriptOptions.NONE);
ensureMachineHasPowerDown(vmName); ExecResponse execResponse = Futures.getUnchecked(execFuture);
return vm; checkState(execResponse.getExitStatus() == 0);
}
private void configureOsInstallationWithKeyboardSequence(String vmName, String installationKeySequence) { logger.debug(
Iterable<List<Integer>> scancodelist = transform(Splitter.on(" ").split(installationKeySequence), "<< installation of image complete. Powering down node(%s)",
new StringToKeyCode()); vmName);
for (List<Integer> scancodes : scancodelist) { machineController.ensureMachineHasPowerDown(vmName);
machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, new SendScancodes(scancodes)); return vm;
} }
}
/** private void configureOsInstallationWithKeyboardSequence(String vmName,
* ensureMachineHasPowerDown needs to have this delay just to ensure that the machine is String installationKeySequence) {
* completely powered off Iterable<List<Integer>> scancodelist = transform(Splitter.on(" ")
* .split(installationKeySequence), new StringToKeyCode());
* @param vmName
*/
private void ensureMachineHasPowerDown(String vmName) {
while (!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.POWERED_OFF)) {
try {
machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, new Function<ISession, Void>() {
@Override
public Void apply(ISession session) {
IProgress powerDownProgress = session.getConsole().powerDown();
powerDownProgress.waitForCompletion(-1);
return null;
}
});
} 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")) {
return;
} else if (e.getMessage().contains("VirtualBox error: The object is not ready")) {
continue;
} else {
throw e;
}
}
}
}
private void ensureMachineIsLaunched(String vmName) { for (List<Integer> scancodes : scancodelist) {
machineUtils.applyForMachine(vmName, new LaunchMachineIfNotAlreadyRunning(manager.get(), executionType, "")); machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared,
} new SendScancodes(scancodes));
}
}
} }

View File

@ -19,58 +19,123 @@
package org.jclouds.virtualbox.functions; package org.jclouds.virtualbox.functions;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.List;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; 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.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.net.IPSocket; import org.jclouds.net.IPSocket;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import org.jclouds.virtualbox.domain.BridgedIf;
import org.jclouds.virtualbox.statements.GetIPAddressFromMAC;
import org.jclouds.virtualbox.statements.ScanNetworkWithPing;
import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.INetworkAdapter; import org.virtualbox_4_1.INetworkAdapter;
import org.virtualbox_4_1.NetworkAttachmentType;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.inject.Inject; import com.google.inject.Inject;
@Singleton @Singleton
public class IMachineToSshClient implements Function<IMachine, SshClient> { public class IMachineToSshClient implements Function<IMachine, SshClient> {
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private final SshClient.Factory sshClientFactory; private final SshClient.Factory sshClientFactory;
private final RunScriptOnNode.Factory scriptRunnerFactory;
private final Supplier<NodeMetadata> hostSupplier;
@Inject @Inject
public IMachineToSshClient(SshClient.Factory sshClientFactory) { public IMachineToSshClient(SshClient.Factory sshClientFactory,
this.sshClientFactory = sshClientFactory; RunScriptOnNode.Factory scriptRunnerFactory,
} Supplier<NodeMetadata> hostSupplier) {
this.sshClientFactory = sshClientFactory;
this.scriptRunnerFactory = scriptRunnerFactory;
this.hostSupplier = hostSupplier;
}
@Override @Override
public SshClient apply(final IMachine vm) { public SshClient apply(final IMachine vm) {
INetworkAdapter networkAdapter = vm.getNetworkAdapter(0L); INetworkAdapter networkAdapter = vm.getNetworkAdapter(0L);
SshClient client = null; SshClient client = null;
checkNotNull(networkAdapter); checkNotNull(networkAdapter);
for (String nameProtocolnumberAddressInboudportGuestTargetport : networkAdapter.getNatDriver().getRedirects()) {
Iterable<String> stuff = Splitter.on(',').split(nameProtocolnumberAddressInboudportGuestTargetport); String clientIpAddress = null;
String protocolNumber = Iterables.get(stuff, 1); String sshPort = "22";
String hostAddress = Iterables.get(stuff, 2);
String inboundPort = Iterables.get(stuff, 3); // TODO: we need a way to align the default login credentials
String targetPort = Iterables.get(stuff, 5); // from the iso with the vmspec -> IMachineToNodeMetadata using YamlImage ?
// TODO: we need a way to align the default login credentials from the iso with the LoginCredentials loginCredentials = LoginCredentials.builder()
// vmspec .user("toor").password("password").authenticateSudo(true)
if ("1".equals(protocolNumber) && "22".equals(targetPort)) { .build();
client = sshClientFactory.create(new IPSocket(hostAddress, Integer.parseInt(inboundPort)), LoginCredentials
.builder().user("toor").password("password").authenticateSudo(true).build()); if (networkAdapter.getAttachmentType()
} .equals(NetworkAttachmentType.NAT)) {
} for (String nameProtocolnumberAddressInboudportGuestTargetport : networkAdapter
checkNotNull(client); .getNatDriver().getRedirects()) {
return client; Iterable<String> stuff = Splitter.on(',').split(
} nameProtocolnumberAddressInboudportGuestTargetport);
String protocolNumber = Iterables.get(stuff, 1);
String hostAddress = Iterables.get(stuff, 2);
String inboundPort = Iterables.get(stuff, 3);
String targetPort = Iterables.get(stuff, 5);
if ("1".equals(protocolNumber) && "22".equals(targetPort)) {
clientIpAddress = hostAddress;
sshPort = inboundPort;
}
}
} else if (networkAdapter.getAttachmentType().equals(
NetworkAttachmentType.Bridged)) {
String network = "1.1.1.1";
clientIpAddress = getIpAddressFromBridgedNIC(networkAdapter, network);
}
checkNotNull(clientIpAddress, "clientIpAddress");
client = sshClientFactory.create(
new IPSocket(clientIpAddress, Integer.parseInt(sshPort)),
loginCredentials);
checkNotNull(client);
return client;
}
private String getIpAddressFromBridgedNIC(INetworkAdapter networkAdapter,
String network) {
// RetrieveActiveBridgedInterfaces
List<BridgedIf> activeBridgedInterfaces = new RetrieveActiveBridgedInterfaces(scriptRunnerFactory).apply(hostSupplier.get());
BridgedIf activeBrigedIf = checkNotNull(Iterables.get(activeBridgedInterfaces, 0), "activeBridgrdIf");
network = activeBrigedIf.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,15 +23,18 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials; import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.virtualbox.domain.BridgedIf;
import org.jclouds.virtualbox.domain.CloneSpec; import org.jclouds.virtualbox.domain.CloneSpec;
import org.jclouds.virtualbox.domain.ExecutionType; import org.jclouds.virtualbox.domain.ExecutionType;
import org.jclouds.virtualbox.domain.Master; import org.jclouds.virtualbox.domain.Master;
@ -52,95 +55,148 @@ import com.google.common.base.Function;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@Singleton @Singleton
public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials<IMachine>> { public class NodeCreator implements
Function<NodeSpec, NodeAndInitialCredentials<IMachine>> {
// TODO parameterize // TODO parameterize
public static final int NODE_PORT_INIT = 3000; public static final int NODE_PORT_INIT = 3000;
// TODO parameterize // TODO parameterize
public static final String VMS_NETWORK = "33.33.33."; public static final String VMS_NETWORK = "33.33.33.";
// TODO parameterize // TODO parameterize
public static final String HOST_ONLY_IFACE_NAME = "vboxnet0"; public static final String HOST_ONLY_IFACE_NAME = "vboxnet0";
// TODO parameterize // TODO parameterize
public static final boolean USE_LINKED = true; public static final boolean USE_LINKED = true;
private final Supplier<VirtualBoxManager> manager; private final Supplier<VirtualBoxManager> manager;
private final Function<CloneSpec, IMachine> cloner; private final Function<CloneSpec, IMachine> cloner;
private final AtomicInteger nodes; private final AtomicInteger nodePorts;
private MachineUtils machineUtils; private final AtomicInteger nodeIps;
private Function<IMachine, NodeMetadata> imachineToNodeMetadata; private MachineUtils machineUtils;
private Function<IMachine, NodeMetadata> imachineToNodeMetadata;
@Inject private final RunScriptOnNode.Factory scriptRunnerFactory;
public NodeCreator(Supplier<VirtualBoxManager> manager, Function<CloneSpec, IMachine> cloner, private final Supplier<NodeMetadata> hostSupplier;
MachineUtils machineUtils, Function<IMachine, NodeMetadata> imachineToNodeMetadata) {
this.manager = manager;
this.cloner = cloner;
this.nodes = new AtomicInteger(0);
this.machineUtils = machineUtils;
this.imachineToNodeMetadata = imachineToNodeMetadata;
}
/** @Inject
* Creates a clone based on the {@link NodeSpec}. It is synchronized because it needs sole access public NodeCreator(Supplier<VirtualBoxManager> manager,
* to the master. Could be improved by locking on a master basis (would allow concurrent cloning Function<CloneSpec, IMachine> cloner, MachineUtils machineUtils,
* as long as form different masters." Function<IMachine, NodeMetadata> imachineToNodeMetadata,
*/ RunScriptOnNode.Factory scriptRunnerFactory,
@Override Supplier<NodeMetadata> hostSupplier) {
public synchronized NodeAndInitialCredentials<IMachine> apply(NodeSpec nodeSpec) { this.manager = manager;
this.cloner = cloner;
this.nodePorts = new AtomicInteger(NODE_PORT_INIT);
this.nodeIps = new AtomicInteger(1);
this.machineUtils = machineUtils;
this.imachineToNodeMetadata = imachineToNodeMetadata;
this.scriptRunnerFactory = scriptRunnerFactory;
this.hostSupplier = hostSupplier;
checkNotNull(nodeSpec, "NodeSpec"); }
Master master = nodeSpec.getMaster(); @Override
checkNotNull(master, "Master"); public NodeAndInitialCredentials<IMachine> apply(NodeSpec nodeSpec) {
if (master.getMachine().getCurrentSnapshot() != null) { checkNotNull(nodeSpec, "NodeSpec");
ISession session;
try {
session = manager.get().openMachineSession(master.getMachine());
} catch (Exception e) {
throw new RuntimeException("error opening vbox machine session: " + e.getMessage(), e);
}
session.getConsole().deleteSnapshot(master.getMachine().getCurrentSnapshot().getId());
session.unlockMachine();
}
String masterNameWithoutPrefix = master.getSpec().getVmSpec().getVmName().replace(VIRTUALBOX_IMAGE_PREFIX, ""); Master master = nodeSpec.getMaster();
checkNotNull(master, "Master");
String cloneName = VIRTUALBOX_NODE_PREFIX + masterNameWithoutPrefix + "-" + nodeSpec.getTag() + "-" if (master.getMachine().getCurrentSnapshot() != null) {
+ nodeSpec.getName(); ISession session;
try {
session = manager.get().openMachineSession(master.getMachine());
} catch (Exception e) {
throw new RuntimeException(
"error opening vbox machine session: " + e.getMessage(),
e);
}
session.getConsole().deleteSnapshot(
master.getMachine().getCurrentSnapshot().getId());
session.unlockMachine();
}
String masterNameWithoutPrefix = master.getSpec().getVmSpec()
.getVmName().replace(VIRTUALBOX_IMAGE_PREFIX, "");
VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(512).cleanUpMode(CleanupMode.Full) String cloneName = VIRTUALBOX_NODE_PREFIX + masterNameWithoutPrefix
.forceOverwrite(true).build(); + "-" + nodeSpec.getTag() + "-" + nodeSpec.getName();
NetworkAdapter natAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT) VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName)
.tcpRedirectRule("127.0.0.1", NODE_PORT_INIT + this.nodes.getAndIncrement(), "", 22).build(); .memoryMB(512).cleanUpMode(CleanupMode.Full)
.forceOverwrite(true).build();
NetworkInterfaceCard natIfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(natAdapter).slot(0L).build();
// CASE NAT + HOST-ONLY
NetworkAdapter natAdapter = NetworkAdapter
.builder()
.networkAttachmentType(NetworkAttachmentType.NAT)
.tcpRedirectRule("127.0.0.1", this.nodePorts.getAndIncrement(),
"", 22).build();
NetworkInterfaceCard natIfaceCard = NetworkInterfaceCard.builder()
.addNetworkAdapter(natAdapter).slot(0L).build();
NetworkAdapter hostOnlyAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.HostOnly) NetworkAdapter hostOnlyAdapter = NetworkAdapter.builder()
.staticIp(VMS_NETWORK + this.nodes.getAndIncrement()).build(); .networkAttachmentType(NetworkAttachmentType.HostOnly)
.staticIp(VMS_NETWORK + this.nodeIps.getAndIncrement()).build();
NetworkInterfaceCard hostOnlyIfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(hostOnlyAdapter) NetworkInterfaceCard hostOnlyIfaceCard = NetworkInterfaceCard.builder()
.addHostInterfaceName(HOST_ONLY_IFACE_NAME).slot(1L).build(); .addNetworkAdapter(hostOnlyAdapter)
.addHostInterfaceName(HOST_ONLY_IFACE_NAME).slot(1L).build();
NetworkSpec networkSpec = createNetworkSpecForHostOnlyNATNICs(natIfaceCard, hostOnlyIfaceCard);
////
// CASE BRIDGED
//NetworkSpec networkSpec = createNetworkSpecForBridgedNIC();
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(natIfaceCard).addNIC(hostOnlyIfaceCard).build(); CloneSpec cloneSpec = CloneSpec.builder().linked(USE_LINKED)
.master(master.getMachine()).network(networkSpec)
.vm(cloneVmSpec).build();
CloneSpec cloneSpec = CloneSpec.builder().linked(USE_LINKED).master(master.getMachine()).network(networkSpec) IMachine cloned = cloner.apply(cloneSpec);
.vm(cloneVmSpec).build();
IMachine cloned = cloner.apply(cloneSpec); new LaunchMachineIfNotAlreadyRunning(manager.get(), ExecutionType.GUI,
"").apply(cloned);
new LaunchMachineIfNotAlreadyRunning(manager.get(), ExecutionType.GUI, "").apply(cloned);
// CASE NAT + HOST-ONLY
machineUtils.runScriptOnNode(imachineToNodeMetadata.apply(cloned),
new SetIpAddress(hostOnlyIfaceCard), RunScriptOptions.NONE);
////
machineUtils.runScriptOnNode(imachineToNodeMetadata.apply(cloned), new SetIpAddress(hostOnlyIfaceCard), // TODO get credentials from somewhere else (they are also HC in
RunScriptOptions.NONE); // IMachineToSshClient)
NodeAndInitialCredentials<IMachine> nodeAndInitialCredentials = new NodeAndInitialCredentials<IMachine>(
cloned, cloneName, LoginCredentials.builder().user("toor")
.password("password").authenticateSudo(true).build());
// TODO get credentials from somewhere else (they are also HC in IMachineToSshClient) return nodeAndInitialCredentials;
NodeAndInitialCredentials<IMachine> nodeAndInitialCredentials = new NodeAndInitialCredentials<IMachine>(cloned, }
cloneName, LoginCredentials.builder().user("toor").password("password").authenticateSudo(true).build());
return nodeAndInitialCredentials; private NetworkSpec createNetworkSpecForHostOnlyNATNICs(NetworkInterfaceCard natIfaceCard, NetworkInterfaceCard hostOnlyIfaceCard) {
} return NetworkSpec.builder().addNIC(natIfaceCard)
.addNIC(hostOnlyIfaceCard).build();
}
private NetworkSpec createNetworkSpecForBridgedNIC() {
List<BridgedIf> activeBridgedInterfaces = new RetrieveActiveBridgedInterfaces(
scriptRunnerFactory).apply(hostSupplier.get());
BridgedIf bridgedActiveInterface = checkNotNull(
activeBridgedInterfaces.get(0), "activeBridgedIf");
NetworkAdapter bridgedAdapter = NetworkAdapter.builder()
.networkAttachmentType(NetworkAttachmentType.Bridged).build();
NetworkInterfaceCard bridgedNIC = NetworkInterfaceCard.builder()
.addNetworkAdapter(bridgedAdapter)
.addHostInterfaceName(bridgedActiveInterface.getName())
.slot(0L).build();
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(bridgedNIC)
.build();
return networkSpec;
}
} }

View File

@ -37,6 +37,7 @@ import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.virtualbox.domain.BridgedIf;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@ -50,67 +51,56 @@ import com.google.inject.name.Named;
/** /**
* @author Andrea Turli * @author Andrea Turli
*/ */
public class RetrieveActiveBridgedInterfaces implements Function<NodeMetadata, List<String>> { public class RetrieveActiveBridgedInterfaces implements Function<NodeMetadata, List<BridgedIf>> {
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private final Factory runScriptOnNodeFactory; private final Factory runScriptOnNodeFactory;
@Inject @Inject
public RetrieveActiveBridgedInterfaces(Factory runScriptOnNodeFactory) { public RetrieveActiveBridgedInterfaces(Factory runScriptOnNodeFactory) {
this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory"); this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
} }
@Override @Override
public List<String> apply(NodeMetadata host) { public List<BridgedIf> apply(NodeMetadata host) {
// Bridged Network // Bridged Network
Statement command = Statements.exec("VBoxManage list bridgedifs"); Statement command = Statements.exec("VBoxManage list bridgedifs");
String bridgedIfBlocks = runScriptOnNodeFactory.create(host, command, runAsRoot(false).wrapInInitScript(false)) String bridgedIfBlocks = runScriptOnNodeFactory.create(host, command, runAsRoot(false).wrapInInitScript(false))
.init().call().getOutput(); .init().call().getOutput();
List<String> bridgedInterfaces = retrieveBridgedInterfaceNames(bridgedIfBlocks); List<BridgedIf> bridgedInterfaces = retrieveBridgedInterfaceNames(bridgedIfBlocks);
checkNotNull(bridgedInterfaces); checkNotNull(bridgedInterfaces);
// union of bridgedNetwork with inet up and !loopback // union of bridgedNetwork with inet up and !loopback
List<String> activeNetworkInterfaceNames = Lists.newArrayList(); List<BridgedIf> activeNetworkInterfaces = Lists.newArrayList();
try { try {
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces(); Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface inet : Collections.list(nets)) { for (NetworkInterface inet : Collections.list(nets)) {
Iterable<String> filteredBridgedInterface = filter(bridgedInterfaces, new IsActiveBridgedInterface(inet)); Iterable<BridgedIf> filteredBridgedInterface = filter(bridgedInterfaces, new IsActiveBridgedInterface(inet));
Iterables.addAll(activeNetworkInterfaceNames, filteredBridgedInterface); Iterables.addAll(activeNetworkInterfaces, filteredBridgedInterface);
} }
} catch (SocketException e) { } catch (SocketException e) {
logger.error(e, "Problem in listing network interfaces."); logger.error(e, "Problem in listing network interfaces.");
Throwables.propagate(e); Throwables.propagate(e);
assert false; assert false;
} }
return activeNetworkInterfaceNames; return activeNetworkInterfaces;
} }
protected static List<String> retrieveBridgedInterfaceNames(String bridgedIfBlocks) { protected static List<BridgedIf> retrieveBridgedInterfaceNames(String bridgedIfBlocks) {
List<String> bridgedInterfaceNames = Lists.newArrayList(); List<BridgedIf> bridgedInterfaces = Lists.newArrayList();
// separate the different bridge block // separate the different bridge block
for (String bridgedIfBlock : Splitter.on(Pattern.compile("(?m)^[ \t]*\r?\n")).split(bridgedIfBlocks)) { for (String bridgedIfBlock : Splitter.on(Pattern.compile("(?m)^[ \t]*\r?\n")).split(bridgedIfBlocks)) {
if(!bridgedIfBlock.isEmpty())
Iterable<String> bridgedIfName = filter(Splitter.on("\n").split(bridgedIfBlock), new Predicate<String>() { bridgedInterfaces.add(new BridgedIfStringToBridgedIf().apply(bridgedIfBlock));
@Override
public boolean apply(String arg0) {
return arg0.startsWith("Name:");
}
});
for (String bridgedInterfaceName : bridgedIfName) {
for (String string : Splitter.on("Name:").split(bridgedInterfaceName)) {
if (!string.isEmpty())
bridgedInterfaceNames.add(string.trim());
}
}
} }
return bridgedInterfaceNames; return bridgedInterfaces;
} }
private class IsActiveBridgedInterface implements Predicate<String> { private class IsActiveBridgedInterface implements Predicate<BridgedIf> {
private NetworkInterface networkInterface; private NetworkInterface networkInterface;
@ -119,10 +109,12 @@ public class RetrieveActiveBridgedInterfaces implements Function<NodeMetadata, L
} }
@Override @Override
public boolean apply(String bridgedInterfaceName) { public boolean apply(BridgedIf bridgedInterface) {
try { try {
return (bridgedInterfaceName.startsWith(networkInterface.getDisplayName()) && networkInterface.isUp() && !networkInterface return (bridgedInterface.getName().startsWith(networkInterface.getDisplayName()) &&
.isLoopback()); bridgedInterface.getStatus().equals("Up") &&
networkInterface.isUp() &&
!networkInterface.isLoopback());
} catch (SocketException e) { } catch (SocketException e) {
logger.error(e, "Problem in listing network interfaces."); logger.error(e, "Problem in listing network interfaces.");
Throwables.propagate(e); Throwables.propagate(e);

View File

@ -1,3 +1,22 @@
/**
* 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.predicates; package org.jclouds.virtualbox.predicates;
import javax.annotation.Resource; import javax.annotation.Resource;

View File

@ -0,0 +1,92 @@
/**
* 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 javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
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.IProgress;
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.LockType;
import org.virtualbox_4_1.VirtualBoxManager;
import org.virtualbox_4_1.jaxws.MachineState;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.inject.Inject;
/**
* Utilities to manage VirtualBox machine life cycle.
*
* @author Adrian Cole, Mattias Holmqvist, Andrea Turli
*/
@Singleton
public class MachineController {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final Supplier<VirtualBoxManager> manager;
private final MachineUtils machineUtils;
private final ExecutionType executionType;
@Inject
public MachineController(Supplier<VirtualBoxManager> manager, MachineUtils machineUtils, ExecutionType executionType) {
this.manager = manager;
this.machineUtils = machineUtils;
this.executionType = executionType;
}
public void ensureMachineIsLaunched(String vmName) {
machineUtils.applyForMachine(vmName, new LaunchMachineIfNotAlreadyRunning(manager.get(), executionType, ""));
}
public void ensureMachineHasPowerDown(String vmName) {
while (!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.POWERED_OFF)) {
try {
machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, new Function<ISession, Void>() {
@Override
public Void apply(ISession session) {
IProgress powerDownProgress = session.getConsole().powerDown();
powerDownProgress.waitForCompletion(-1);
return null;
}
});
} 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")) {
return;
} else if (e.getMessage().contains("VirtualBox error: The object is not ready")) {
continue;
} else {
throw e;
}
}
}
}
}

View File

@ -1,9 +1,9 @@
function cleanupUdevIfNeeded { function cleanupUdevIfNeeded {
unset OSNAME; # unset OSNAME;
local OSNAME=`lsb_release -d -s | cut -d ' ' -f 1`; shift # local OSNAME=`lsb_release -d -s | cut -d ' ' -f 1`; shift
if [ $OSNAME = 'Ubuntu' ] # if [ $OSNAME = 'Ubuntu' ]
if [ -f '/etc/udev/rules.d/70-persistent-net.rules']
then then
echo "OS is Ubuntu"
rm /etc/udev/rules.d/70-persistent-net.rules; rm /etc/udev/rules.d/70-persistent-net.rules;
mkdir /etc/udev/rules.d/70-persistent-net.rules; mkdir /etc/udev/rules.d/70-persistent-net.rules;
rm -rf /dev/.udev/; rm -rf /dev/.udev/;

View File

@ -30,14 +30,11 @@ import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.byon.Node;
import org.jclouds.byon.config.CacheNodeStoreModule;
import org.jclouds.compute.BaseVersionedServiceLiveTest; import org.jclouds.compute.BaseVersionedServiceLiveTest;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ComputeServiceContextFactory; import org.jclouds.compute.ComputeServiceContextFactory;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.strategy.PrioritizeCredentialsFromTemplate; import org.jclouds.compute.strategy.PrioritizeCredentialsFromTemplate;
import org.jclouds.concurrent.MoreExecutors; import org.jclouds.concurrent.MoreExecutors;
@ -49,21 +46,16 @@ import org.jclouds.virtualbox.domain.IsoSpec;
import org.jclouds.virtualbox.domain.Master; import org.jclouds.virtualbox.domain.Master;
import org.jclouds.virtualbox.domain.VmSpec; import org.jclouds.virtualbox.domain.VmSpec;
import org.jclouds.virtualbox.functions.admin.UnregisterMachineIfExistsAndDeleteItsMedia; import org.jclouds.virtualbox.functions.admin.UnregisterMachineIfExistsAndDeleteItsMedia;
import org.jclouds.virtualbox.util.MachineController;
import org.jclouds.virtualbox.util.MachineUtils; import org.jclouds.virtualbox.util.MachineUtils;
import org.testng.annotations.AfterClass; import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.LockType;
import org.virtualbox_4_1.VirtualBoxManager; import org.virtualbox_4_1.VirtualBoxManager;
import org.virtualbox_4_1.jaxws.MachineState;
import com.google.common.base.Function;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.inject.Module; import com.google.inject.Module;
@ -80,6 +72,9 @@ public class BaseVirtualBoxClientLiveTest extends BaseVersionedServiceLiveTest {
} }
protected ComputeServiceContext context; protected ComputeServiceContext context;
@Inject
protected MachineController machineController;
@Inject @Inject
protected Supplier<VirtualBoxManager> manager; protected Supplier<VirtualBoxManager> manager;
@ -160,30 +155,7 @@ public class BaseVirtualBoxClientLiveTest extends BaseVersionedServiceLiveTest {
new UnregisterMachineIfExistsAndDeleteItsMedia(vmSpecification)); new UnregisterMachineIfExistsAndDeleteItsMedia(vmSpecification));
} }
protected void ensureMachineHasPowerDown(String vmName) {
while (!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.POWERED_OFF)) {
try {
machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, new Function<ISession, Void>() {
@Override
public Void apply(ISession session) {
IProgress powerDownProgress = session.getConsole().powerDown();
powerDownProgress.waitForCompletion(-1);
return null;
}
});
} 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")) {
return;
} else if (e.getMessage().contains("VirtualBox error: The object is not ready")) {
continue;
} else {
throw e;
}
}
}
}
public String adminDisk(String vmName) { public String adminDisk(String vmName) {
return workingDir + File.separator + vmName + ".vdi"; return workingDir + File.separator + vmName + ".vdi";

View File

@ -0,0 +1,52 @@
package org.jclouds.virtualbox.functions;
import static org.testng.Assert.assertEquals;
import org.jclouds.virtualbox.domain.BridgedIf;
import org.testng.annotations.Test;
@Test(groups = "live", singleThreaded = true, testName = "BridgedIfStringToBridgedIfTest")
public class BridgedIfStringToBridgedIfTest {
private static final String en0 = "Name: en0: Ethernet\n" +
"GUID: 00306e65-0000-4000-8000-3c0754205d2f\n" +
"Dhcp: Disabled\n" +
"IPAddress: 192.168.56.1\n" +
"NetworkMask: 255.255.255.0\n" +
"IPV6Address: \n" +
"IPV6NetworkMaskPrefixLength: 0\n" +
"HardwareAddress: 3c:07:54:20:5d:2f\n" +
"MediumType: Ethernet\n" +
"Status: Up\n" +
"VBoxNetworkName: HostInterfaceNetworking-en0: Ethernet\n";
private static final String en1 = "Name: en1: Wi-Fi (AirPort)\n" +
"GUID: 00316e65-0000-4000-8000-28cfdaf2917a\n" +
"Dhcp: Disabled\n" +
"IPAddress: 192.168.57.1\n" +
"NetworkMask: 255.255.255.0\n" +
"IPV6Address: \n" +
"IPV6NetworkMaskPrefixLength: 0\n" +
"HardwareAddress: 28:cf:da:f2:91:7a\n" +
"MediumType: Ethernet\n" +
"Status: Up\n" +
"VBoxNetworkName: HostInterfaceNetworking-en1: Wi-Fi (AirPort)\n";
private static final String p2p0 = "Name: p2p0\n" +
"GUID: 30703270-0000-4000-8000-0acfdaf2917a\n" +
"Dhcp: Disabled\n" +
"IPAddress: 192.168.58.1\n" +
"NetworkMask: 255.255.255.0\n" +
"IPV6Address: \n" +
"IPV6NetworkMaskPrefixLength: 0\n" +
"HardwareAddress: 0a:cf:da:f2:91:7a\n" +
"MediumType: Ethernet\n" +
"Status: Down\n" +
"VBoxNetworkName: HostInterfaceNetworking-p2p0\n";
@Test
public void transformRawBridgedifToBridgedIf() {
BridgedIf bridgedIfEn1 = new BridgedIfStringToBridgedIf().apply(en1);
assertEquals(bridgedIfEn1.getName(), "en1: Wi-Fi (AirPort)");
}
}

View File

@ -26,8 +26,6 @@ import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTA
import java.util.Map; import java.util.Map;
import javax.annotation.Nullable;
import org.jclouds.compute.config.BaseComputeServiceContextModule; import org.jclouds.compute.config.BaseComputeServiceContextModule;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
@ -153,21 +151,11 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest {
})); }));
} finally { } finally {
for (VmSpec spec : ImmutableSet.of(vmSpecification)) { for (VmSpec spec : ImmutableSet.of(vmSpecification)) {
ensureMachineHasPowerDown(spec.getVmName()); machineController.ensureMachineHasPowerDown(spec.getVmName());
} }
} }
} }
private Function<Image, String> extractId() {
return new Function<Image, String>() {
@Override
public String apply(@Nullable Image input) {
return input.getId();
}
};
}
private IMachine getVmWithGuestAdditionsInstalled() { private IMachine getVmWithGuestAdditionsInstalled() {
try { try {
Injector injector = context.utils().injector(); Injector injector = context.utils().injector();

View File

@ -25,6 +25,7 @@ import static org.testng.Assert.assertFalse;
import java.util.List; import java.util.List;
import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest; import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest;
import org.jclouds.virtualbox.domain.BridgedIf;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -51,13 +52,13 @@ public class RetrieveActiveBridgedInterfacesLiveTest extends BaseVirtualBoxClien
@Test @Test
public void retrieveBridgedInterfaceNamesTest() { public void retrieveBridgedInterfaceNamesTest() {
List<String> activeBridgedInterfaceNames = retrieveBridgedInterfaceNames(TEST1); List<BridgedIf> activeBridgedInterfaces = retrieveBridgedInterfaceNames(TEST1);
assertEquals(activeBridgedInterfaceNames, expectedBridgedInterfaces); assertEquals(activeBridgedInterfaces, expectedBridgedInterfaces);
} }
@Test @Test
public void retrieveAvailableBridgedInterfaceInfoTest() { public void retrieveAvailableBridgedInterfaceInfoTest() {
List<String> bridgedInterface = context.utils().injector().getInstance(RetrieveActiveBridgedInterfaces.class) List<BridgedIf> bridgedInterface = context.utils().injector().getInstance(RetrieveActiveBridgedInterfaces.class)
.apply(host.get()); .apply(host.get());
assertFalse(bridgedInterface.isEmpty()); assertFalse(bridgedInterface.isEmpty());
} }

View File

@ -40,7 +40,6 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import org.virtualbox_4_1.CleanupMode; import org.virtualbox_4_1.CleanupMode;
import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISession; import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.LockType; import org.virtualbox_4_1.LockType;
import org.virtualbox_4_1.NetworkAttachmentType; import org.virtualbox_4_1.NetworkAttachmentType;
@ -123,7 +122,7 @@ public class GuestAdditionsInstallerLiveTest extends
})); }));
} finally { } finally {
for (VmSpec spec : ImmutableSet.of(sourceMachineSpec.getVmSpec())) { for (VmSpec spec : ImmutableSet.of(sourceMachineSpec.getVmSpec())) {
ensureMachineHasPowerDown(spec.getVmName()); machineController.ensureMachineHasPowerDown(spec.getVmName());
undoVm(spec); undoVm(spec);
} }
} }