issue 384: added support for creation of hostOnly interface with DHCP enabled

This commit is contained in:
Andrea Turli 2012-03-30 19:18:22 +01:00
parent af309232ad
commit 50815d2483
2 changed files with 115 additions and 7 deletions

View File

@ -172,7 +172,7 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
}
}
nodeMetadataBuilder.publicAddresses(publicIpAddresses);
nodeMetadataBuilder.privateAddresses(privateIpAddresses);
nodeMetadataBuilder.privateAddresses(publicIpAddresses);
return nodeMetadataBuilder;
}

View File

@ -1,4 +1,4 @@
/**
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
@ -20,19 +20,26 @@
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_IMAGE_PREFIX;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_NAME_SEPARATOR;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX;
import java.util.List;
import javax.inject.Inject;
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.domain.LoginCredentials;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.virtualbox.config.VirtualBoxComputeServiceContextModule;
import org.jclouds.virtualbox.domain.CloneSpec;
import org.jclouds.virtualbox.domain.Master;
@ -46,6 +53,9 @@ import org.jclouds.virtualbox.statements.EnableNetworkInterface;
import org.jclouds.virtualbox.util.MachineController;
import org.jclouds.virtualbox.util.MachineUtils;
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;
@ -53,8 +63,10 @@ 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.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* Creates nodes, by cloning a master vm and based on the provided {@link NodeSpec}. Must be
@ -66,19 +78,23 @@ import com.google.common.collect.ImmutableSet;
@Singleton
public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials<IMachine>> {
// TODO parameterize
public static final String HOST_ONLY_IFACE_NAME = "vboxnet0";
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;
@Inject
public NodeCreator(Supplier<VirtualBoxManager> manager, Function<CloneSpec, IMachine> cloner,
public NodeCreator(Supplier<VirtualBoxManager> manager, Function<CloneSpec, IMachine> cloner, Factory runScriptOnNodeFactory,
Supplier<NodeMetadata> host,
MachineUtils machineUtils, RunScriptOnNode.Factory scriptRunnerFactory, MachineController machineController) {
this.manager = manager;
this.cloner = cloner;
this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
this.host = checkNotNull(host, "host");
this.machineUtils = machineUtils;
this.machineController = machineController;
}
@ -118,8 +134,11 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
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(HOST_ONLY_IFACE_NAME).slot(0L).build();
.addHostInterfaceName(hostOnlyIfName).slot(0L).build();
NetworkSpec networkSpec = createNetworkSpecForHostOnlyNATNICs(natIfaceCard, hostOnlyIfaceCard);
@ -165,5 +184,94 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
NetworkInterfaceCard hostOnlyIfaceCard) {
return NetworkSpec.builder().addNIC(natIfaceCard).addNIC(hostOnlyIfaceCard).build();
}
/**
* @return
*/
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 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";
ExecResponse response = runScriptOnNodeFactory
.create(host.get(),
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);
/*
runScriptOnNodeFactory
.create(host.get(),
Statements.exec(String.format("VBoxManage hostonlyif ipconfig %s --ip %s",
hostOnlyIfName, hostOnlyIfIpAddress)), runAsRoot(false).wrapInInitScript(false)).init().call();
*/
}
private String createHostOnlyIf() {
final String hostOnlyIfName;
ExecResponse createHostOnyResponse = runScriptOnNodeFactory
.create(host.get(), Statements.exec("VBoxManage hostonlyif create"),
runAsRoot(false).wrapInInitScript(false)).init().call();
String output = createHostOnyResponse.getOutput();
checkState(createHostOnyResponse.getExitStatus()==0);
checkState(output.contains("'"), "cannot create hostonlyif");
hostOnlyIfName = output.substring(output.indexOf("'") + 1, output.lastIndexOf("'"));
return hostOnlyIfName;
}
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;
}
}