Merge pull request #834 from andreaturli/virtualbox

issue 384: added support for ubuntu12.04; prepared for supporting remote host
This commit is contained in:
Adrian Cole 2012-09-12 08:00:41 -07:00
commit 80f6101e1f
29 changed files with 911 additions and 494 deletions

View File

@ -1,9 +1,17 @@
#Setup
Have virtualbox 4.1.8 installed.
Have virtualbox 4.1.20r80170 installed.
Have an ssh daemon with passwordless login to localhost (i.e. "ssh [me]@localhost" must work without password).
To achieve that, be sure you have your ssh public key (at System.getProperty("user.home") + "/.ssh/id_rsa") in your '.ssh/authorized_keys'.
Please look at [this example]http://www.linuxproblem.org/art_9.html for more details.
You can have also specify '-Dvirtualbox.identity' and '-Dvirtualbox.credential' if you want to use a username and password of your local machine.
In order to make available a preseed file, jclouds-vbox will start a PreseedServer at `http://localhost:23232` that will serve a preseed.cfg file.
Make sure your firewall rules are not blocking this port.
If you need to override this default you can use -Djclouds.virtualbox.preconfigurationurl=http://localhost:PORT/preseed.cfg, with a different PORT.
That's it!
@ -17,7 +25,7 @@ Enjoy local cloud goodness by running:
> (use 'org.jclouds.compute2)
> (import 'org.jclouds.scriptbuilder.statements.login.AdminAccess)
> (def compute (compute-service "virtualbox" "admin" "12345" :sshj :slf4j))
> (def compute (compute-service "virtualbox" "user" "password" :sshj :slf4j))
> (create-nodes compute "local-cluster" 2 (build-template compute { :run-script (AdminAccess/standard) } ))
--------------
@ -39,7 +47,7 @@ It *should* behave as any other provider, if not please report.
- jclouds-vbox is still at alpha stage please report any issues you find.
- jclouds-vbox has been mostly tested on Mac OSX, it might work on Linux iff vbox is running and correctly set up, but it won't work on windows for the moment.
- cached isos, vm's and most configs are kept at ~/.jclouds-vbox/ by default.
- cached isos, vm's and most configs are kept at ~/.jclouds-vbox/ by default, you can override -Dtest.virtualbox.workingDir=/path/to/your/workingDir.
- jclouds-vbox assumes vbox has the default host-only network vboxnet0, that the network is in 192.168.86.0/255.255.255.0 and that the host has address 1 in this network.
--------------

View File

@ -37,10 +37,10 @@
<properties>
<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.8r75467</test.virtualbox.build-version>
<test.virtualbox.build-version>4.1.20r80170</test.virtualbox.build-version>
<test.virtualbox.identity>administrator</test.virtualbox.identity>
<test.virtualbox.credential>12345</test.virtualbox.credential>
<test.virtualbox.template>imageId=test-ubuntu-11.10-i386,loginUser=toor:password,authenticateSudo=true</test.virtualbox.template>
<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>
<jclouds.osgi.import>org.jclouds*;version="${project.version}",*</jclouds.osgi.import>
</properties>
@ -136,6 +136,7 @@
</goals>
<configuration>
<threadCount>1</threadCount>
<parallel>false</parallel>
<systemPropertyVariables>
<test.virtualbox.endpoint>${test.virtualbox.endpoint}</test.virtualbox.endpoint>
<test.virtualbox.api-version>${test.virtualbox.api-version}</test.virtualbox.api-version>

View File

@ -20,6 +20,8 @@ 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;
@ -81,7 +83,13 @@ public class VirtualBoxApiMetadata extends BaseApiMetadata {
properties.put(VIRTUALBOX_IMAGES_DESCRIPTOR, yamlDescriptor);
properties.put(VIRTUALBOX_PRECONFIGURATION_URL, "http://10.0.2.2:23232/preseed.cfg");
properties.setProperty(TEMPLATE, "osFamily=UBUNTU,osVersionMatches=11.10,os64Bit=true,osArchMatches=x86,loginUser=toor:password,authenticateSudo=true");
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)));
return properties;
}
@ -93,8 +101,8 @@ public class VirtualBoxApiMetadata extends BaseApiMetadata {
.identityName("User")
.credentialName("Password")
.documentation(URI.create("https://www.virtualbox.org/sdkref/index.html"))
.defaultIdentity("administrator")
.defaultCredential("12345")
.defaultIdentity(System.getProperty("user.name"))
.defaultCredential("CHANGE_ME")
.defaultEndpoint("http://localhost:18083/")
.documentation(URI.create("https://github.com/jclouds/jclouds/tree/master/apis/byon"))
// later version not in maven, yet

View File

@ -35,6 +35,7 @@ import org.jclouds.domain.LocationScope;
import org.jclouds.domain.LoginCredentials;
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.io.Files;
@ -79,7 +80,7 @@ import com.google.inject.Provides;
public class HardcodeLocalhostAsNodeMetadataSupplier extends AbstractModule {
public static final String HOST_ID = "host";
public static final String HOSTNAME = System.getenv("HOSTNAME");
public static final String HOSTNAME = Strings.nullToEmpty(System.getenv("HOSTNAME"));
/**
* Lazy so that we don't hang up the injector reading a file
@ -91,9 +92,7 @@ public class HardcodeLocalhostAsNodeMetadataSupplier extends AbstractModule {
@Override
public NodeMetadata get() {
String privateKey = readRsaIdentity();
return new NodeMetadataBuilder()
.id(HOST_ID)
.name("host installing virtualbox")
@ -110,9 +109,9 @@ public class HardcodeLocalhostAsNodeMetadataSupplier extends AbstractModule {
.description(HOSTNAME)
.build())
.credentials(LoginCredentials.builder()
.user(System.getProperty("user.name"))
.privateKey(privateKey)
.build())
.user(System.getProperty("user.name"))
.privateKey(privateKey)
.build())
.build();
}

View File

@ -150,7 +150,10 @@ public class VirtualBoxComputeServiceContextModule extends
@Override
public VirtualBoxManager apply(Supplier<NodeMetadata> nodeSupplier) {
return VirtualBoxManager.createInstance(nodeSupplier.get().getId());
if(nodeSupplier.get().getId() != null)
return VirtualBoxManager.createInstance(nodeSupplier.get().getId());
return VirtualBoxManager.createInstance("");
}
@Override

View File

@ -62,4 +62,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";
}

View File

@ -118,6 +118,7 @@ public class YamlImage {
public String os_family;
public String os_description;
public String os_version;
public String iso_md5;
public String iso;
public String keystroke_sequence;
public String preseed_cfg;

View File

@ -21,6 +21,7 @@ package org.jclouds.virtualbox.functions;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.Resource;
import javax.inject.Named;
@ -61,6 +62,8 @@ 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) {
@ -104,15 +107,13 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements Fu
if (isLinkedClone)
options.add(CloneOptions.Link);
// TODO snapshot name
ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "snapshotName", "snapshotDesc", logger)
.apply(master);
// clone
IProgress progress = currentSnapshot.getMachine().cloneTo(clonedMachine, CloneMode.MachineState, options);
ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager,
"snapshotName", "snapshotDesc", logger).apply(master);
IProgress progress = currentSnapshot.getMachine().cloneTo(clonedMachine,
CloneMode.MachineState, options);
progress.waitForCompletion(-1);
logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName()));
logger.debug(String.format("Machine %s is cloned correctly",
clonedMachine.getName()));
// memory may not be the same as the master vm
clonedMachine.setMemorySize(cloneSpec.getVmSpec().getMemory());

View File

@ -42,7 +42,9 @@ import org.jclouds.virtualbox.domain.VmSpec;
import org.jclouds.virtualbox.statements.InstallGuestAdditions;
import org.jclouds.virtualbox.util.MachineController;
import org.jclouds.virtualbox.util.MachineUtils;
import org.virtualbox_4_1.DeviceType;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IMediumAttachment;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
@ -88,19 +90,14 @@ public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
@Override
public IMachine apply(MasterSpec masterSpec) {
VmSpec vmSpec = masterSpec.getVmSpec();
IsoSpec isoSpec = masterSpec.getIsoSpec();
String vmName = vmSpec.getVmName();
IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists.apply(masterSpec);
// Launch machine and wait for it to come online
machineController.ensureMachineIsLaunched(vmName);
String installationKeySequence = isoSpec.getInstallationKeySequence().replace("PRECONFIGURATION_URL",
preconfigurationUrl);
configureOsInstallationWithKeyboardSequence(vmName, installationKeySequence);
// the OS installation is a long process: let's delay the check for ssh of 30 sec
@ -111,11 +108,8 @@ public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
}
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);
logger.debug(">> awaiting post-installation actions on vm: %s", vmName);
@ -129,9 +123,17 @@ public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
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);
}
});
for (IMediumAttachment iMediumAttachment : mediumAttachments) {
machineUtils.writeLockMachineAndApply(vm.getName(), new DetachDistroMediumFromMachine(
iMediumAttachment.getController(), iMediumAttachment.getPort(), iMediumAttachment.getDevice()));
}
return vm;
}

View File

@ -0,0 +1,83 @@
/**
* 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.net.URI;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
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.logging.Logger;
import org.jclouds.rest.annotations.Credential;
import org.jclouds.rest.annotations.Identity;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@Singleton
public class HardcodedHostToHostNodeMetadata implements
Function<NodeMetadata, NodeMetadata> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final Supplier<URI> providerSupplier;
private final String username;
private final String password;
@Inject
public HardcodedHostToHostNodeMetadata(
@Provider Supplier<URI> providerSupplier,
@Nullable @Identity String identity,
@Nullable @Credential String credential) {
this.providerSupplier = checkNotNull(providerSupplier,
"endpoint to virtualbox websrvd is needed");
this.username = identity;
this.password = credential.equals("CHANGE_ME") ? "" : credential;
}
@Override
public NodeMetadata apply(NodeMetadata host) {
LoginCredentials.Builder credentialsBuilder = LoginCredentials.builder(
host.getCredentials()).user(username);
if (!password.isEmpty())
credentialsBuilder.password(password);
return NodeMetadataBuilder
.fromNodeMetadata(host)
.credentials(credentialsBuilder.build())
.publicAddresses(ImmutableList.of(providerSupplier.get().getHost()))
.build();
}
}

View File

@ -46,7 +46,6 @@ import org.virtualbox_4_1.NetworkAttachmentType;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@ -82,7 +81,6 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
NodeMetadataBuilder nodeMetadataBuilder = new NodeMetadataBuilder();
nodeMetadataBuilder.name(name).ids(vm.getName()).group(group);
// TODO Set up location properly
LocationBuilder locationBuilder = new LocationBuilder();
locationBuilder.description("");
@ -96,41 +94,8 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
if (nodeState == null)
nodeState = Status.UNRECOGNIZED;
nodeMetadataBuilder.status(nodeState);
/*
// nat adapter
INetworkAdapter natAdapter = vm.getNetworkAdapter(0l);
checkNotNull(natAdapter, "slot 0 networkadapter");
checkState(natAdapter.getAttachmentType() == NetworkAttachmentType.NAT,
"expecting slot 0 to be a NAT attachment type (was: " + natAdapter.getAttachmentType() + ")");
int ipTermination = 0;
int inPort = 0;
String hostAddress = "";
nodeMetadataBuilder.publicAddresses(ImmutableSet.of(natAdapter.getNatDriver().getHostIP()));
for (String nameProtocolnumberAddressInboudportGuestTargetport : natAdapter.getNatDriver().getRedirects()) {
Iterable<String> stuff = Splitter.on(',').split(nameProtocolnumberAddressInboudportGuestTargetport);
String protocolNumber = Iterables.get(stuff, 1);
hostAddress = Iterables.get(stuff, 2);
String inboundPort = Iterables.get(stuff, 3);
String targetPort = Iterables.get(stuff, 5);
if ("1".equals(protocolNumber) && "22".equals(targetPort)) {
inPort = Integer.parseInt(inboundPort);
ipTermination = inPort % NodeCreator.NODE_PORT_INIT + 2;
}
}
// only masters use 2222 port
if (inPort == MastersLoadingCache.MASTER_PORT) {
nodeMetadataBuilder.publicAddresses(ImmutableSet.of(hostAddress)).loginPort(inPort);
} else {
nodeMetadataBuilder.privateAddresses(ImmutableSet.of((NodeCreator.VMS_NETWORK + ipTermination) + ""));
nodeMetadataBuilder.publicAddresses(ImmutableSet.of((NodeCreator.VMS_NETWORK + ipTermination) + ""));
}
*/
nodeMetadataBuilder = getIpAddresses(vm, nodeMetadataBuilder);
LoginCredentials loginCredentials = new LoginCredentials("toor", "password", null, true);
nodeMetadataBuilder.credentials(loginCredentials);
@ -144,7 +109,9 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
INetworkAdapter adapter = vm.getNetworkAdapter(slot);
if(adapter != null) {
if (adapter.getAttachmentType() == NetworkAttachmentType.NAT) {
publicIpAddresses.add(adapter.getNatDriver().getHostIP());
String hostIP = adapter.getNatDriver().getHostIP();
if(!hostIP.isEmpty())
publicIpAddresses.add(hostIP);
for (String nameProtocolnumberAddressInboudportGuestTargetport : adapter.getNatDriver().getRedirects()) {
Iterable<String> stuff = Splitter.on(',').split(nameProtocolnumberAddressInboudportGuestTargetport);
String protocolNumber = Iterables.get(stuff, 1);
@ -153,26 +120,25 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
String targetPort = Iterables.get(stuff, 5);
if ("1".equals(protocolNumber) && "22".equals(targetPort)) {
int inPort = Integer.parseInt(inboundPort);
nodeMetadataBuilder.publicAddresses(ImmutableSet.of(hostAddress)).loginPort(inPort);
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.getIpAddressFromBridgedNIC(vm.getName());
String clientIpAddress = machineUtils.getIpAddressFromFirstNIC(vm.getName());
//privateIpAddresses.add(clientIpAddress);
publicIpAddresses.add(clientIpAddress);
} else if (adapter.getAttachmentType() == NetworkAttachmentType.HostOnly) {
String clientIpAddress = machineUtils.getIpAddressFromHostOnlyNIC(vm.getName());
String clientIpAddress = machineUtils.getIpAddressFromFirstNIC(vm.getName());
publicIpAddresses.add(clientIpAddress);
}
}
}
nodeMetadataBuilder.publicAddresses(publicIpAddresses);
nodeMetadataBuilder.privateAddresses(publicIpAddresses);
return nodeMetadataBuilder;
}

View File

@ -20,6 +20,8 @@ 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;
@ -35,6 +37,7 @@ 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;
@ -82,10 +85,11 @@ public class IMachineToSshClient implements Function<IMachine, SshClient> {
String clientIpAddress = null;
String sshPort = "22";
// TODO: we need a way to align the default login credentials
// from the iso with the vmspec -> IMachineToNodeMetadata using YamlImage ?
String guestIdentity = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_IDENTITY);
String guestCredential = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_CREDENTIAL);
LoginCredentials loginCredentials = LoginCredentials.builder()
.user("toor").password("password").authenticateSudo(true)
.user(guestIdentity)
.password(guestCredential).authenticateSudo(true)
.build();
if (networkAdapter.getAttachmentType()
@ -109,7 +113,7 @@ public class IMachineToSshClient implements Function<IMachine, SshClient> {
clientIpAddress = getIpAddressFromBridgedNIC(networkAdapter, network);
} else if (networkAdapter.getAttachmentType().equals(
NetworkAttachmentType.HostOnly)) {
clientIpAddress = machineUtils.getIpAddressFromHostOnlyNIC(vm.getName());
clientIpAddress = machineUtils.getIpAddressFromFirstNIC(vm.getName());
}
checkNotNull(clientIpAddress, "clientIpAddress");

View File

@ -0,0 +1,95 @@
/**
* 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 java.util.concurrent.ExecutionException;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.virtualbox.util.MachineUtils;
import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Supplier;
import com.google.common.cache.AbstractLoadingCache;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Maps;
/**
* 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
*
*/
@Singleton
public class IpAddressesLoadingCache extends
AbstractLoadingCache<String, String> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final Map<String, String> masters = Maps.newHashMap();
private final Supplier<VirtualBoxManager> manager;
@Inject
public IpAddressesLoadingCache(Supplier<VirtualBoxManager> manager) {
this.manager = checkNotNull(manager, "vboxmanager");
}
@Override
public synchronized String get(String idOrName) throws ExecutionException {
if (masters.containsKey(idOrName)) {
return masters.get(idOrName);
}
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");
}
if (previousIp.equals(currentIp)) {
count++;
}
previousIp = currentIp;
}
masters.put(idOrName, currentIp);
return currentIp;
}
@Override
public String getIfPresent(Object key) {
return masters.get((String) key);
}
}

View File

@ -22,6 +22,7 @@ package org.jclouds.virtualbox.functions;
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 static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAULT_DIR;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
@ -32,6 +33,8 @@ import static org.jclouds.virtualbox.util.MachineUtils.machineNotFoundException;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
@ -42,10 +45,17 @@ import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.callables.RunScriptOnNode.Factory;
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.location.Provider;
import org.jclouds.logging.Logger;
import org.jclouds.rest.annotations.BuildVersion;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.virtualbox.domain.HardDisk;
import org.jclouds.virtualbox.domain.IsoSpec;
import org.jclouds.virtualbox.domain.Master;
@ -57,6 +67,8 @@ import org.jclouds.virtualbox.domain.StorageController;
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.testng.collections.Lists;
import org.virtualbox_4_1.CleanupMode;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.NetworkAttachmentType;
@ -71,178 +83,236 @@ import com.google.common.cache.AbstractLoadingCache;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.net.HostAndPort;
/**
* A {@link LoadingCache} for masters. If the requested master has been previously created this
* returns it, if not it coordinates its creation including downloading isos and creating
* cache/config directories. This also implements {@link Supplier} in order to provide jetty with
* the current image (only one master can be created at a time).
* A {@link LoadingCache} for masters. If the requested master has been
* previously created this returns it, if not it coordinates its creation
* including downloading isos and creating cache/config directories. This also
* implements {@link Supplier} in order to provide jetty with the current image
* (only one master can be created at a time).
*
* @author dralves
* @author dralves, andrea turli
*
*/
@Singleton
public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
// TODO parameterize
public static final int MASTER_PORT = 2222;
public static final String HOST_ONLY_IFACE_NAME = "vboxnet0";
// TODO parameterize
public static final int MASTER_PORT = 2222;
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final Map<String, Master> masters = Maps.newHashMap();
private final Function<MasterSpec, IMachine> masterCreatorAndInstaller;
private final Map<String, YamlImage> imageMapping;
private final String workingDir;
private final String installationKeySequence;
private final String isosDir;
private final Supplier<VirtualBoxManager> manager;
private final Function<URI, File> isoDownloader;
private final String version;
private final String preconfigurationUrl;
private final Map<String, Master> masters = Maps.newHashMap();
private final Function<MasterSpec, IMachine> masterCreatorAndInstaller;
private final Map<String, YamlImage> imageMapping;
private final String workingDir;
private final String installationKeySequence;
private final String isosDir;
private final Supplier<VirtualBoxManager> manager;
private final String version;
private final String preconfigurationUrl;
@Inject
public MastersLoadingCache(@BuildVersion String version,
@Named(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE) String installationKeySequence,
@Named(VIRTUALBOX_PRECONFIGURATION_URL) String preconfigurationUrl,
@Named(VIRTUALBOX_WORKINGDIR) String workingDir, Function<MasterSpec, IMachine> masterLoader,
Supplier<Map<Image, YamlImage>> yamlMapper, Supplier<VirtualBoxManager> manager,
Function<URI, File> isoDownloader) {
checkNotNull(version, "version");
checkNotNull(installationKeySequence, "installationKeySequence");
checkNotNull(manager, "vboxmanager");
this.manager = manager;
this.masterCreatorAndInstaller = masterLoader;
this.installationKeySequence = installationKeySequence;
this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR : workingDir;
this.isosDir = workingDir + File.separator + "isos";
this.imageMapping = Maps.newLinkedHashMap();
for (Entry<Image, YamlImage> entry : yamlMapper.get().entrySet()) {
this.imageMapping.put(entry.getKey().getId(), entry.getValue());
private final Factory runScriptOnNodeFactory;
private final RetryIfSocketNotYetOpen socketTester;
private final Supplier<NodeMetadata> host;
private final Supplier<URI> providerSupplier;
private final HardcodedHostToHostNodeMetadata hardcodedHostToHostNodeMetadata;
@Inject
public MastersLoadingCache(
@BuildVersion String version,
@Named(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE) String installationKeySequence,
@Named(VIRTUALBOX_PRECONFIGURATION_URL) String preconfigurationUrl,
@Named(VIRTUALBOX_WORKINGDIR) String workingDir,
Function<MasterSpec, IMachine> masterLoader,
Supplier<Map<Image, YamlImage>> yamlMapper,
Supplier<VirtualBoxManager> manager,
Factory runScriptOnNodeFactory,
RetryIfSocketNotYetOpen socketTester, Supplier<NodeMetadata> host,
@Provider Supplier<URI> providerSupplier,
HardcodedHostToHostNodeMetadata hardcodedHostToHostNodeMetadata) {
checkNotNull(version, "version");
checkNotNull(installationKeySequence, "installationKeySequence");
checkNotNull(manager, "vboxmanager");
this.manager = manager;
this.masterCreatorAndInstaller = masterLoader;
this.installationKeySequence = installationKeySequence;
this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR
: workingDir;
this.isosDir = workingDir + File.separator + "isos";
this.imageMapping = Maps.newLinkedHashMap();
for (Entry<Image, YamlImage> entry : yamlMapper.get().entrySet()) {
this.imageMapping.put(entry.getKey().getId(), entry.getValue());
}
this.version = Iterables.get(Splitter.on('r').split(version), 0);
this.preconfigurationUrl = preconfigurationUrl;
this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory,
"runScriptOnNodeFactory");
this.socketTester = checkNotNull(socketTester, "socketTester");
this.socketTester.seconds(3L);
this.host = checkNotNull(host, "host");
this.providerSupplier = checkNotNull(providerSupplier,
"endpoint to virtualbox websrvd is needed");
this.hardcodedHostToHostNodeMetadata = hardcodedHostToHostNodeMetadata;
}
@PostConstruct
public void createCacheDirStructure() {
if (!new File(workingDir).exists()) {
new File(workingDir, "isos").mkdirs();
}
}
@Override
public synchronized Master get(Image key) throws ExecutionException {
// check if we have loaded this machine before
if (masters.containsKey(key.getId())) {
return masters.get(key.getId());
}
checkState(!key.getId().contains(VIRTUALBOX_NODE_NAME_SEPARATOR),
"master image names cannot contain \""
+ VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
String vmName = VIRTUALBOX_IMAGE_PREFIX + key.getId();
IMachine masterMachine;
Master master;
// ready the preseed file server
PreseedCfgServer server = new PreseedCfgServer();
try {
// try and find a master machine in vbox
masterMachine = manager.get().getVBox().findMachine(vmName);
master = Master.builder().machine(masterMachine).build();
} catch (VBoxException e) {
if (machineNotFoundException(e)) {
// machine was not found try to build one from a yaml file
YamlImage currentImage = checkNotNull(imageMapping.get(key.getId()), "currentImage");
URI preseedServer;
try {
preseedServer = new URI(preconfigurationUrl);
if (!socketTester.apply(HostAndPort.fromParts(preseedServer.getHost(),
preseedServer.getPort()))) {
server.start(preconfigurationUrl, currentImage.preseed_cfg);
}
} catch (URISyntaxException e1) {
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 {
throw e;
}
} finally {
server.stop();
}
masters.put(key.getId(), master);
return master;
}
private MasterSpec buildMasterSpecFromYaml(YamlImage currentImage,
String vmName) throws ExecutionException {
String guestAdditionsFileName = String.format(
"VBoxGuestAdditions_%s.iso", version);
String guestAdditionsIso = String.format("%s/%s", isosDir,
guestAdditionsFileName);
String guestAdditionsUri = "http://download.virtualbox.org/virtualbox/"
+ version + "/" + guestAdditionsFileName;
if (!new File(guestAdditionsIso).exists()) {
getFilePathOrDownload(guestAdditionsUri, null);
}
// check if the iso is here, download if not
String localIsoUrl = checkNotNull(getFilePathOrDownload(currentImage.iso, currentImage.iso_md5), "distro iso");
String adminDisk = workingDir + File.separator + vmName + ".vdi";
HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk)
.autoDelete(true).controllerPort(0).deviceSlot(1).build();
StorageController ideController = StorageController.builder()
.name("IDE Controller").bus(StorageBus.IDE)
.attachISO(0, 0, localIsoUrl).attachHardDisk(hardDisk)
.attachISO(1, 0, guestAdditionsIso).build();
VmSpec vmSpecification = VmSpec.builder().id(currentImage.id)
.name(vmName).memoryMB(512).osTypeId("")
.controller(ideController).forceOverwrite(true)
.cleanUpMode(CleanupMode.Full).build();
NetworkAdapter networkAdapter = NetworkAdapter
.builder()
.networkAttachmentType(NetworkAttachmentType.NAT)
.tcpRedirectRule(providerSupplier.get().getHost(), MASTER_PORT,
"", 22).build();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard
.builder().addNetworkAdapter(networkAdapter).slot(0L).build();
NetworkSpec networkSpec = NetworkSpec.builder()
.addNIC(networkInterfaceCard).build();
return MasterSpec
.builder()
.vm(vmSpecification)
.iso(IsoSpec
.builder()
.sourcePath(localIsoUrl)
.installationScript(
installationKeySequence.replace("HOSTNAME",
vmSpecification.getVmName())).build())
.network(networkSpec).build();
}
@Override
public synchronized Master getIfPresent(Object key) {
checkArgument(key instanceof Image,
"this cache is for entries who's keys are Images");
Image image = Image.class.cast(key);
if (masters.containsKey(image.getId())) {
return masters.get(image.getId());
}
return null;
}
private String getFilePathOrDownload(String httpUrl, String md5)
throws ExecutionException {
String fileName = httpUrl.substring(httpUrl.lastIndexOf('/') + 1,
httpUrl.length());
URI provider = providerSupplier.get();
if (!socketTester.apply(HostAndPort.fromParts(provider.getHost(),
provider.getPort()))) {
throw new RuntimeException("could not connect to virtualbox");
}
this.version = Iterables.get(Splitter.on('r').split(version), 0);
this.isoDownloader = isoDownloader;
this.preconfigurationUrl = preconfigurationUrl;
}
File file = new File(isosDir, fileName);
List<Statement> statements = Lists.newArrayList();
statements.add(Statements.saveHttpResponseTo(URI.create(httpUrl),
isosDir, fileName));
StatementList statementList = new StatementList(statements);
NodeMetadata hostNodeMetadata = hardcodedHostToHostNodeMetadata
.apply(host.get());
runScriptOnNodeFactory
.create(hostNodeMetadata, statementList, runAsRoot(false)).init()
.call();
@PostConstruct
public void createCacheDirStructure() {
if (!new File(workingDir).exists()) {
new File(workingDir, "isos").mkdirs();
ExecResponse response = runScriptOnNodeFactory
.create(
hostNodeMetadata,
Statements.exec("md5 " + isosDir + File.separator + fileName),
runAsRoot(false)).init().call();
if (md5 != null) {
if (!Iterables.get(
Splitter.on("=").trimResults().split(response.getOutput()), 1)
.equals(md5))
return null;
}
}
@Override
public synchronized Master get(Image key) throws ExecutionException {
// check if we have loaded this machine before
if (masters.containsKey(key.getId())) {
return masters.get(key.getId());
}
checkState(!key.getId().contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "master image names cannot contain \""
+ VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
String vmName = VIRTUALBOX_IMAGE_PREFIX + key.getId();
IMachine masterMachine;
Master master;
// ready the preseed file server
PreseedCfgServer server = new PreseedCfgServer();
try {
// try and find a master machine in vbox
masterMachine = manager.get().getVBox().findMachine(vmName);
master = Master.builder().machine(masterMachine).build();
} catch (VBoxException e) {
if (machineNotFoundException(e)) {
// machine was not found try to build one from a yaml file
YamlImage currentImage = imageMapping.get(key.getId());
checkNotNull(currentImage);
server.start(preconfigurationUrl, currentImage.preseed_cfg);
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 {
throw e;
}
} finally {
server.stop();
}
masters.put(key.getId(), master);
return master;
}
private MasterSpec buildMasterSpecFromYaml(YamlImage currentImage, String vmName) throws ExecutionException {
String guestAdditionsFileName = String.format("VBoxGuestAdditions_%s.iso", version);
String guestAdditionsIso = String.format("%s/%s", isosDir, guestAdditionsFileName);
String guestAdditionsUri = "http://download.virtualbox.org/virtualbox/" + version + "/" + guestAdditionsFileName;
if (!new File(guestAdditionsIso).exists()) {
getFilePathOrDownload(guestAdditionsUri);
}
checkState(new File(guestAdditionsIso).exists(), "guest additions iso does not exist at: " + guestAdditionsIso);
// check if the iso is here, download if not
String localIsoUrl = getFilePathOrDownload(currentImage.iso);
String adminDisk = workingDir + File.separator + vmName + ".vdi";
HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk).autoDelete(true).controllerPort(0).deviceSlot(1)
.build();
StorageController ideController = StorageController.builder().name("IDE Controller").bus(StorageBus.IDE)
.attachISO(0, 0, localIsoUrl).attachHardDisk(hardDisk).attachISO(1, 0, guestAdditionsIso).build();
VmSpec vmSpecification = VmSpec.builder().id(currentImage.id).name(vmName).memoryMB(512).osTypeId("")
.controller(ideController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build();
NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
.tcpRedirectRule("127.0.0.1", MASTER_PORT, "", 22).build();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
.slot(0L).build();
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
return MasterSpec
.builder()
.vm(vmSpecification)
.iso(IsoSpec.builder().sourcePath(localIsoUrl)
.installationScript(installationKeySequence.replace("HOSTNAME", vmSpecification.getVmName()))
.build()).network(networkSpec).build();
}
@Override
public synchronized Master getIfPresent(Object key) {
checkArgument(key instanceof Image, "this cache is for entries who's keys are Images");
Image image = Image.class.cast(key);
if (masters.containsKey(image.getId())) {
return masters.get(image.getId());
}
return null;
}
private String getFilePathOrDownload(String httpUrl) throws ExecutionException {
String fileName = httpUrl.substring(httpUrl.lastIndexOf('/') + 1, httpUrl.length());
File localFile = new File(isosDir, fileName);
if (!localFile.exists()) {
logger.debug("iso not found in cache, downloading: %s", httpUrl);
localFile = isoDownloader.apply(URI.create(httpUrl));
}
checkState(localFile.exists(), "iso file has not been downloaded: " + fileName);
return localFile.getAbsolutePath();
return file.getAbsolutePath();
}
}

View File

@ -22,10 +22,13 @@ 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.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.inject.Inject;
@ -39,7 +42,12 @@ 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.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.virtualbox.config.VirtualBoxComputeServiceContextModule;
import org.jclouds.virtualbox.domain.CloneSpec;
import org.jclouds.virtualbox.domain.Master;
@ -63,8 +71,10 @@ import org.virtualbox_4_1.NetworkAttachmentType;
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.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@ -84,29 +94,36 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
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);
@Inject
public NodeCreator(Supplier<VirtualBoxManager> manager, Function<CloneSpec, IMachine> cloner, Factory runScriptOnNodeFactory,
MachineUtils machineUtils, RunScriptOnNode.Factory scriptRunnerFactory, MachineController machineController,
Supplier<NodeMetadata> host,
MachineUtils machineUtils, RunScriptOnNode.Factory scriptRunnerFactory, MachineController machineController) {
@Provider Supplier<URI> providerSupplier,
@Nullable @Identity String identity,
@Nullable @Credential String credential) {
this.manager = manager;
this.cloner = cloner;
this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
this.host = checkNotNull(host, "host");
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;
}
@Override
public synchronized NodeAndInitialCredentials<IMachine> apply(NodeSpec nodeSpec) {
checkNotNull(nodeSpec, "NodeSpec");
Master master = nodeSpec.getMaster();
checkNotNull(master, "Master");
Master master = checkNotNull(nodeSpec.getMaster(), "Master");
if (master.getMachine().getCurrentSnapshot() != null) {
ISession session;
try {
@ -119,40 +136,32 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
session.unlockMachine();
}
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();
int ram = 512;
if (nodeSpec.getTemplate() != null && nodeSpec.getTemplate().getHardware() != null
&& nodeSpec.getTemplate().getHardware().getRam() > 0) {
ram = nodeSpec.getTemplate().getHardware().getRam();
}
VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(ram).cleanUpMode(CleanupMode.Full)
VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(ram)
.cleanUpMode(CleanupMode.Full)
.forceOverwrite(true).build();
// CASE NAT + HOST-ONLY
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();
NetworkSpec networkSpec = createNetworkSpecForHostOnlyNATNICs(natIfaceCard, hostOnlyIfaceCard);
// case 'vbox host is localhost': NAT + HOST-ONLY
NetworkSpec networkSpec = createNetworkSpecWhenVboxIsLocalhost();
Optional<NetworkInterfaceCard> optionalNatIfaceCard = Iterables.tryFind(
networkSpec.getNetworkInterfaceCards(),
new Predicate<NetworkInterfaceCard>() {
@Override
public boolean apply(NetworkInterfaceCard nic) {
return nic.getNetworkAdapter().getNetworkAttachmentType()
.equals(NetworkAttachmentType.NAT);
}
});
CloneSpec cloneSpec = CloneSpec.builder().linked(true).master(master.getMachine()).network(networkSpec)
.vm(cloneVmSpec).build();
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
@ -160,42 +169,55 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
NodeMetadata partialNodeMetadata = buildPartialNodeMetadata(cloned);
// see DeleteGShadowLock for a detailed explanation
machineUtils.runScriptOnNode(partialNodeMetadata, new DeleteGShadowLock(), RunScriptOptions.NONE);
machineUtils.runScriptOnNode(partialNodeMetadata, new DeleteGShadowLock(), RunScriptOptions.NONE);
// CASE NAT + HOST-ONLY
machineUtils.runScriptOnNode(partialNodeMetadata, new EnableNetworkInterface(natIfaceCard), RunScriptOptions.NONE);
if(optionalNatIfaceCard.isPresent())
machineUtils.runScriptOnNode(partialNodeMetadata, new EnableNetworkInterface(optionalNatIfaceCard.get()), RunScriptOptions.NONE);
// TODO get credentials from somewhere else (they are also HC in
// IMachineToSshClient)
NodeAndInitialCredentials<IMachine> nodeAndInitialCredentials = new NodeAndInitialCredentials<IMachine>(cloned,
cloneName, LoginCredentials.builder().user("toor").password("password").authenticateSudo(true).build());
return nodeAndInitialCredentials;
return new NodeAndInitialCredentials<IMachine>(cloned,
cloneName, LoginCredentials.builder()
.user(guestIdentity)
.password(guestCredential)
.authenticateSudo(true)
.build());
}
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.getIpAddressFromHostOnlyNIC(clone.getName())));
LoginCredentials loginCredentials = new LoginCredentials("toor", "password", null, true);
nodeMetadataBuilder.publicAddresses(ImmutableSet.of(machineUtils.getIpAddressFromFirstNIC(clone.getName())));
LoginCredentials loginCredentials = new LoginCredentials(guestIdentity, guestCredential, 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();
return NetworkSpec.builder()
.addNIC(natIfaceCard)
.addNIC(hostOnlyIfaceCard)
.build();
}
/**
* @return
*/
private String getHostOnlyIfOrCreate() {
IHostNetworkInterface availableHostInterfaceIf = returnExistingHostNetworkInterfaceWithDHCPenabledOrNull(manager
.get().getVBox().getHost().getNetworkInterfaces());
if (availableHostInterfaceIf==null) {
@ -205,7 +227,6 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
} else {
return availableHostInterfaceIf.getName();
}
}
private void assignDHCPtoHostOnlyInterface(final String hostOnlyIfName) {
@ -225,25 +246,21 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
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(host.get(),
.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);
/*
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;
NodeMetadata hostNodeMetadata = getHostNodeMetadata();
ExecResponse createHostOnlyResponse = runScriptOnNodeFactory
.create(host.get(), Statements.exec("VBoxManage hostonlyif create"),
.create(hostNodeMetadata, Statements.exec("VBoxManage hostonlyif create"),
runAsRoot(false).wrapInInitScript(false)).init().call();
String output = createHostOnlyResponse.getOutput();
checkState(createHostOnlyResponse.getExitStatus()==0);
@ -252,6 +269,16 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
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);

View File

@ -24,22 +24,29 @@ 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 javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.callables.RunScriptOnNode.Factory;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.location.Provider;
import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.virtualbox.functions.HardcodedHostToHostNodeMetadata;
import org.jclouds.virtualbox.predicates.RetryIfSocketNotYetOpen;
import org.virtualbox_4_1.SessionState;
import org.virtualbox_4_1.VirtualBoxManager;
import com.beust.jcommander.internal.Lists;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.net.HostAndPort;
@ -57,41 +64,72 @@ public class StartVBoxIfNotAlreadyRunning implements Supplier<VirtualBoxManager>
private final Supplier<URI> providerSupplier;
private final Function<Supplier<NodeMetadata>, VirtualBoxManager> managerForNode;
private transient VirtualBoxManager manager;
private final HardcodedHostToHostNodeMetadata hardcodedHostToHostNodeMetadata;
// the functions and suppliers here are to ensure we don't do heavy i/o in injection
@Inject
public StartVBoxIfNotAlreadyRunning(Function<Supplier<NodeMetadata>, VirtualBoxManager> managerForNode,
Factory runScriptOnNodeFactory, RetryIfSocketNotYetOpen socketTester, Supplier<NodeMetadata> host,
@Provider Supplier<URI> providerSupplier) {
@Provider Supplier<URI> providerSupplier,
HardcodedHostToHostNodeMetadata hardcodedHostToHostNodeMetadata) {
this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
this.socketTester = checkNotNull(socketTester, "socketTester");
this.socketTester.seconds(3L);
this.host = checkNotNull(host, "host");
this.providerSupplier = checkNotNull(providerSupplier, "endpoint to virtualbox websrvd is needed");
this.managerForNode = checkNotNull(managerForNode, "managerForNode");
start();
this.hardcodedHostToHostNodeMetadata = hardcodedHostToHostNodeMetadata;
}
@PostConstruct
public synchronized void start() {
URI provider = providerSupplier.get();
if (!socketTester.apply(HostAndPort.fromParts(provider.getHost(), provider.getPort()))) {
logger.debug("disabling password access");
runScriptOnNodeFactory.create(host.get(), Statements.exec("VBoxManage setproperty websrvauthlibrary null"),
runAsRoot(false).wrapInInitScript(false)).init().call();
logger.debug(">> starting vboxwebsrv");
String vboxwebsrv = "vboxwebsrv -t 10000 -v -b";
runScriptOnNodeFactory.create(host.get(), Statements.exec(vboxwebsrv),
runAsRoot(false).wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv")).init().call();
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()))){
throw new RuntimeException("could not connect to virtualbox");
}
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");
}
logger.debug("disabling password access");
runScriptOnNodeFactory
.create(
hostNodeMetadata,
Statements
.exec("VBoxManage setproperty websrvauthlibrary null"),
runAsRoot(false).wrapInInitScript(false)).init().call();
logger.debug(">> starting vboxwebsrv");
String vboxwebsrv = "vboxwebsrv -t0 -v -b -H "
+ providerSupplier.get().getHost();
runScriptOnNodeFactory
.create(
hostNodeMetadata,
Statements.exec(vboxwebsrv),
runAsRoot(false).wrapInInitScript(false)
.blockOnComplete(false).nameTask("vboxwebsrv")).init()
.call();
if (!socketTester.apply(HostAndPort.fromParts(provider.getHost(),
provider.getPort()))) {
throw new RuntimeException("could not connect to virtualbox");
}
manager = managerForNode.apply(host);
manager.connect(provider.toASCIIString(), "", "");
if (logger.isDebugEnabled())
if (manager.getSessionObject().getState() != SessionState.Unlocked)
logger.warn("manager is not in unlocked state " + manager.getSessionObject().getState());
logger.warn("manager is not in unlocked state "
+ manager.getSessionObject().getState());
}
@Override

View File

@ -63,9 +63,6 @@ public class EnableNetworkInterface implements Statement {
}
private List<Statement> getStatements(String iface) {
/*
* auto eth0
*/
List<Statement> statements = Lists.newArrayList();
statements.add(exec(String.format("echo auto %s >> /etc/network/interfaces", iface))); //
statements.add(exec(String.format("echo iface %s inet dhcp >> /etc/network/interfaces", iface))); //

View File

@ -21,6 +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;
@ -37,6 +38,7 @@ import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.util.Throwables2;
import org.jclouds.virtualbox.functions.IpAddressesLoadingCache;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.LockType;
@ -69,12 +71,14 @@ 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) {
super();
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,
@ -207,9 +211,18 @@ public class MachineUtils {
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());
}
while (true) {
try {
IMachine immutableMachine = manager.get().getVBox().findMachine(machineId);
session = manager.get().getSessionObject();
immutableMachine.lockMachine(session, type);
break;
@ -219,13 +232,13 @@ public class MachineUtils {
return null;
}
count++;
logger.warn(e, "Could not lock machine (try %d of %d). Error: %s", count, retries, e.getMessage());
logger.debug("Could not lock machine (try %d of %d). Error: %s", count, retries, e.getMessage());
if (count == retries) {
throw new RuntimeException(String.format("error locking %s with %s lock: %s", machineId, type,
e.getMessage()), e);
}
try {
Thread.sleep(1000L);
Thread.sleep(count * 1000L);
} catch (InterruptedException e1) {
}
}
@ -265,70 +278,24 @@ public class MachineUtils {
|| e.getMessage().contains("Could not find a registered machine with UUID {");
}
public String getIpAddressFromBridgedNIC(String machineName) {
String ip = "";
int attempt = 0;
while (!isIpv4(ip) && attempt < 10) {
ip = this.lockSessionOnMachineAndApply(machineName, LockType.Shared, new Function<ISession, String>() {
@Override
public String apply(ISession session) {
String ip = session.getMachine().getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP");
return ip;
}
});
attempt++;
long sleepTime = 1000 * attempt;
logger.debug("Instance %s is still not ready. Attempt n:%d. Sleeping for %d millisec", machineName, attempt,
sleepTime);
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
Throwables.propagate(e);
}
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);
}
return ip;
}
private boolean isIpv4(String s) {
Pattern pattern = Pattern.compile(this.IP_V4_ADDRESS_PATTERN);
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 String getIpAddressFromHostOnlyNIC(String machineName) {
// TODO using a caching mechanism to avoid to call every time this vboxmanage api call
String currentIp = "", previousIp = "1.1.1.1";
int attempt = 0, count = 0;
while(count < 5) {
currentIp = "";
attempt = 0;
while (!isIpv4(currentIp) && attempt < 5) {
currentIp = this.lockSessionOnMachineAndApply(machineName, LockType.Shared, new Function<ISession, String>() {
@Override
public String apply(ISession session) {
return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP");
}
});
attempt++;
}
if(previousIp.equals(currentIp)) {
count++;
delayer(500l * (count + 1));
} else {
count = 0;
delayer(5000l);
}
previousIp = currentIp;
}
return currentIp;
}
private void delayer(long millisec) {
try {
Thread.sleep(millisec);
} catch (InterruptedException e) {
Throwables.propagate(e);
}
}
}

View File

@ -133,3 +133,90 @@ images:
# debconf-get-selections --install
#Use mirror
choose-mirror-bin mirror/http/proxy string
- id: ubuntu-12.04.1-amd64
name: ubuntu-12.04.1-server-amd64
description: ubuntu 12.04.1 server (amd64)
os_arch: amd64
os_family: ubuntu
os_description: ubuntu
os_version: 12.04.1
os_64bit: true
iso: http://releases.ubuntu.com/12.04/ubuntu-12.04.1-server-amd64.iso
username: toor
credential: $user
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
keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false
initrd=/install/initrd.gz -- <Enter>
preseed_cfg: |
## Options to set on the command line
d-i debian-installer/locale string en_US.utf8
d-i console-setup/ask_detect boolean false
d-i console-setup/layout string USA
#d-i netcfg/get_hostname string dummy
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
# Continue without a default route
# Not working , specify a dummy in the DHCP
#d-i netcfg/no_default_route boolean
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 base-installer/kernel/override-image string linux-image-2.6.32-21-generic
# Choices: Dialog, Readline, Gnome, Kde, Editor, Noninteractive
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 regular
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
#http://ubuntu-virginia.ubuntuforums.org/showthread.php?p=9626883
#Message: "write the changes to disk and configure lvm preseed"
#http://serverfault.com/questions/189328/ubuntu-kickstart-installation-using-lvm-waits-for-input
#preseed partman-lvm/confirm_nooverwrite 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
## minimum is ssh and ntp
# Individual additional packages to install
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
#d-i apt-setup/use_mirror boolean true
#d-i mirror/country string manual
#choose-mirror-bin mirror/protocol string http
#choose-mirror-bin mirror/http/hostname string 192.168.4.150
#choose-mirror-bin mirror/http/directory string /ubuntu
#choose-mirror-bin mirror/suite select maverick
#d-i debian-installer/allow_unauthenticated string true
choose-mirror-bin mirror/http/proxy string

View File

@ -119,7 +119,7 @@ public class BaseVirtualBoxClientLiveTest extends BaseComputeServiceContextLiveT
protected LoadingCache<Image, Master> mastersCache;
private final ExecutorService singleThreadExec = MoreExecutors.sameThreadExecutor();
private String masterVmName;
private String masterName;
@Override
@ -139,7 +139,7 @@ public class BaseVirtualBoxClientLiveTest extends BaseComputeServiceContextLiveT
Template template = view.getComputeService().templateBuilder().build();
checkNotNull(mastersCache.apply(template.getImage()));
masterVmName = VIRTUALBOX_IMAGE_PREFIX + template.getImage().getId();
masterName = VIRTUALBOX_IMAGE_PREFIX + template.getImage().getId();
isosDir = workingDir + File.separator + "isos";
hostVersion = Iterables.get(Splitter.on('r').split(view.utils().injector().getInstance(Key.get(String.class, BuildVersion.class))), 0);
@ -173,8 +173,6 @@ public class BaseVirtualBoxClientLiveTest extends BaseComputeServiceContextLiveT
}
public MasterSpec getMasterSpecForTest() {
String masterName = "jclouds-image-0x0-" + template.getImageId();
StorageController ideController = StorageController
.builder()
.name("IDE Controller")
@ -220,7 +218,7 @@ public class BaseVirtualBoxClientLiveTest extends BaseComputeServiceContextLiveT
protected void destroyMaster() {
if (System.getProperty(DONT_DESTROY_MASTER) == null
|| !Boolean.parseBoolean(System.getProperty(DONT_DESTROY_MASTER))) {
undoVm(masterVmName);
undoVm(masterName);
}
}

View File

@ -20,7 +20,6 @@ package org.jclouds.virtualbox;
import static org.testng.Assert.assertEquals;
import java.io.File;
import java.net.URI;
import java.net.URL;
import java.util.Map;

View File

@ -51,7 +51,7 @@ public class VirtualBoxComputeServiceAdapterLiveTest extends BaseVirtualBoxClien
@Test
public void testCreatedNodeHasExpectedNameAndWeCanConnectViaSsh() {
String group = "foo";
String name = "foo-ef4";
String name = "foo-ef9";
Template template = view.getComputeService().templateBuilder().build();
machine = adapter.createNodeWithGroupEncodedIntoName(group, name, template);
assertTrue(machine.getNode().getName().contains(group));

View File

@ -36,7 +36,6 @@ 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;
@ -69,10 +68,10 @@ public class VirtualBoxExperimentLiveTest extends BaseVirtualBoxClientLiveTest {
@Test
public void testLaunchCluster() throws RunNodesException {
int numNodes = 2;
int numNodes = 3;
final String clusterName = "test-launch-cluster";
Set<? extends NodeMetadata> nodes = context.getComputeService().createNodesInGroup(clusterName, numNodes,
TemplateOptions.Builder.runScript(AdminAccess.standard()));
TemplateOptions.Builder.overrideLoginUser("toor")); //TODO runScript(AdminAccess.standard()));
assertEquals(numNodes, nodes.size(), "wrong number of nodes");
for (NodeMetadata node : nodes) {
assertTrue(node.getGroup().equals("test-launch-cluster"));

View File

@ -19,6 +19,9 @@
package org.jclouds.virtualbox.compute.extensions;
import java.util.concurrent.ExecutionException;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.extensions.internal.BaseImageExtensionLiveTest;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.testng.annotations.Test;
@ -28,6 +31,22 @@ import com.google.inject.Module;
@Test(groups = "live", singleThreaded = true, testName = "VirtualBoxImageExtensionLiveTest")
public class VirtualBoxImageExtensionLiveTest extends BaseImageExtensionLiveTest {
@Override
public void testDeleteImage() {
// TODO
}
@Override
public void testCreateImage() throws RunNodesException,
InterruptedException, ExecutionException {
// TODO
}
@Override
public void testSpawnNodeFromImage() throws RunNodesException {
// TODO
}
public VirtualBoxImageExtensionLiveTest() {
provider = "virtualbox";
}

View File

@ -24,14 +24,18 @@ import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
import static org.testng.Assert.assertTrue;
import java.net.URI;
import java.util.Map;
import javax.inject.Inject;
import org.jclouds.compute.config.BaseComputeServiceContextModule;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.config.ValueOfConfigurationKeyOrNull;
import org.jclouds.json.Json;
import org.jclouds.json.config.GsonModule;
import org.jclouds.location.Provider;
import org.jclouds.ssh.SshClient;
import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest;
import org.jclouds.virtualbox.domain.CloneSpec;
@ -49,13 +53,13 @@ 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.NetworkAttachmentType;
import org.virtualbox_4_1.StorageBus;
import com.google.common.base.CaseFormat;
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.inject.Guice;
import com.google.inject.Injector;
@ -77,42 +81,9 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest {
private MasterSpec machineSpec;
private String instanceName;
/*
@Override
@BeforeClass(groups = "live")
public void setupClient() {
super.setupClient();
this.vmName = VIRTUALBOX_IMAGE_PREFIX
+ CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName());
HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk(vmName)).autoDelete(true).controllerPort(0)
.deviceSlot(1).build();
StorageController ideController = StorageController.builder().name("IDE Controller").bus(StorageBus.IDE)
.attachISO(0, 0, operatingSystemIso).attachHardDisk(hardDisk).attachISO(1, 1, guestAdditionsIso).build();
vmSpecification = VmSpec.builder().id(vmName).name(vmName).memoryMB(512).osTypeId("").controller(ideController)
.forceOverwrite(true).cleanUpMode(CleanupMode.Full).build();
injector = context.utils().injector();
Function<String, String> configProperties = injector.getInstance(ValueOfConfigurationKeyOrNull.class);
NetworkAdapter natAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
.tcpRedirectRule("127.0.0.1", 2222, "", 22).build();
NetworkInterfaceCard networkInterfaceCard1 = NetworkInterfaceCard.builder().slot(0l)
.addNetworkAdapter(natAdapter).build();
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard1).build();
masterSpec = MasterSpec
.builder()
.vm(vmSpecification)
.iso(IsoSpec
.builder()
.sourcePath(operatingSystemIso)
.installationScript(
configProperties.apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE).replace("HOSTNAME",
vmSpecification.getVmName())).build()).network(networkSpec).build();
}*/
@Inject
@Provider
protected Supplier<URI> providerSupplier;
@Override
@BeforeClass(groups = "live")
@ -142,11 +113,10 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest {
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();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.HostOnly)
.build();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
.addHostInterfaceName("vboxnet0").slot(0L).build();
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
machineSpec = MasterSpec.builder().iso(isoSpec).vm(instanceVmSpec).network(networkSpec).build();
}
@ -164,12 +134,7 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest {
checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh",
machine.getName());
String version = machineUtils.sharedLockMachineAndApplyToSession(machine.getName(), new Function<ISession, String>() {
@Override
public String apply(ISession session) {
return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestAdd/Version");
}
});
String version = machine.getGuestPropertyValue("/VirtualBox/GuestAdd/Version");
assertTrue(version != null && !version.isEmpty());
} finally {
@ -193,7 +158,6 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest {
Injector injector = view.utils().injector();
return injector.getInstance(CreateAndInstallVm.class).apply(masterSpecForTest);
} catch (IllegalStateException e) {
// already created
return manager.get().getVBox().findMachine(masterSpecForTest.getVmSpec().getVmId());
}
}

View File

@ -64,7 +64,7 @@ public class StartVBoxIfNotAlreadyRunningLiveTest {
replay(manager, runScriptOnNodeFactory, client);
new StartVBoxIfNotAlreadyRunning((Function) Functions.constant(manager), runScriptOnNodeFactory, client,
Suppliers.ofInstance(host), Suppliers.ofInstance(provider)).start();
Suppliers.ofInstance(host), Suppliers.ofInstance(provider), null).start();
verify(manager, runScriptOnNodeFactory, client);
@ -84,26 +84,26 @@ public class StartVBoxIfNotAlreadyRunningLiveTest {
expect(client.seconds(3)).andReturn(client);
expect(client.apply(HostAndPort.fromParts(provider.getHost(), provider.getPort()))).andReturn(false).once().andReturn(true).once();
expect(
runScriptOnNodeFactory.create(host, Statements.exec("VBoxManage setproperty websrvauthlibrary null"),
expect(runScriptOnNodeFactory.create(host,
Statements.exec("VBoxManage setproperty websrvauthlibrary null"),
runAsRoot(false).wrapInInitScript(false))).andReturn(runScriptOnNode);
expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
expect(
runScriptOnNodeFactory.create(host, Statements.exec("vboxwebsrv -t 10000 -v -b"), runAsRoot(false)
.wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv"))).andReturn(
runScriptOnNode);
expect(runScriptOnNodeFactory.create(host,
Statements.exec("vboxwebsrv -t 10000 -v -b -H localhost"), runAsRoot(false)
.wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv")))
.andReturn(runScriptOnNode);
expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
manager.connect(provider.toASCIIString(), "", "");
expectLastCall().anyTimes();
replay(manager, runScriptOnNodeFactory, runScriptOnNode, client);
new StartVBoxIfNotAlreadyRunning((Function) Functions.constant(manager), runScriptOnNodeFactory, client,
Suppliers.ofInstance(host), Suppliers.ofInstance(provider));
verify(manager, runScriptOnNodeFactory, runScriptOnNode, client);
Suppliers.ofInstance(host), Suppliers.ofInstance(provider), null);
verify(manager, runScriptOnNodeFactory, runScriptOnNode, client);
}
}

View File

@ -24,9 +24,6 @@ import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
import static org.testng.Assert.assertTrue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jclouds.config.ValueOfConfigurationKeyOrNull;
import org.jclouds.ssh.SshClient;
import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest;
@ -42,11 +39,12 @@ 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.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.NetworkAttachmentType;
import org.virtualbox_4_1.StorageBus;
@ -67,6 +65,7 @@ public class GuestAdditionsInstallerLiveTest extends BaseVirtualBoxClientLiveTes
private Predicate<SshClient> sshResponds;
private MasterSpec machineSpec;
private IpAddressesLoadingCache ipAddressesLoadingCache;
@Override
@BeforeClass(groups = "live")
@ -118,21 +117,10 @@ 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.sharedLockMachineAndApplyToSession(machine.getName(),
new Function<ISession, Boolean>() {
@Override
public Boolean apply(ISession session) {
String s = session.getMachine().getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP");
return isIpv4(s);
}
assertTrue(MachineUtils.isIpv4(ipAddressesLoadingCache.apply(machine.getName())));
private boolean isIpv4(String s) {
Pattern pattern = Pattern.compile(machineUtils.IP_V4_ADDRESS_PATTERN);
Matcher matcher = pattern.matcher(s);
return matcher.matches();
}
}));
} finally {
for (String vmNameOrId : ImmutableSet.of(machine.getName())) {
machineController.ensureMachineHasPowerDown(vmNameOrId);

View File

@ -77,21 +77,25 @@ public class MachineControllerLiveTest extends BaseVirtualBoxClientLiveTest {
.cleanUpMode(CleanupMode.Full).controller(ideController).forceOverwrite(true).build();
Injector injector = view.utils().injector();
Function<String, String> configProperties = injector.getInstance(ValueOfConfigurationKeyOrNull.class);
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();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
.build();
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
machineSpec = MasterSpec.builder().iso(isoSpec).vm(instanceVmSpec).network(networkSpec).build();
NetworkAdapter networkAdapter = NetworkAdapter.builder()
.networkAttachmentType(NetworkAttachmentType.HostOnly).build();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard
.builder().addNetworkAdapter(networkAdapter)
.addHostInterfaceName("vboxnet0").slot(0L).build();
NetworkSpec networkSpec = NetworkSpec.builder()
.addNIC(networkInterfaceCard).build();
machineSpec = MasterSpec.builder().iso(isoSpec).vm(instanceVmSpec)
.network(networkSpec).build();
}
@Test
@ -106,8 +110,8 @@ public class MachineControllerLiveTest extends BaseVirtualBoxClientLiveTest {
@Test(dependsOnMethods="testEnsureMachineisLaunchedAndSessionIsUnlocked")
public void testEnsureMachineCanBePoweredOffMoreThanOneTimeAndSessionIsUnlocked() {
ISession cloneMachineSession = machineController.ensureMachineHasPowerDown(instanceName);
cloneMachineSession = machineController.ensureMachineHasPowerDown(instanceName);
assertTrue(cloneMachineSession.getState() == SessionState.Unlocked);
SessionState state = cloneMachineSession.getState();
assertTrue(state.equals(SessionState.Unlocked));
}
private IMachine cloneFromMaster() {

View File

@ -66,7 +66,7 @@ images:
# debconf-get-selections --install
#Use mirror
choose-mirror-bin mirror/http/proxy string
- id: test-ubuntu-11.10-i386
- id: ubuntu-11.10-i386
name: ubuntu-11.10-server-i386
description: ubuntu 11.10 server (i386)
os_arch: x86
@ -133,3 +133,89 @@ images:
# debconf-get-selections --install
#Use mirror
choose-mirror-bin mirror/http/proxy string
- id: ubuntu-12.04.1-amd64
name: ubuntu-12.04.1-server-amd64
description: ubuntu 12.04.1 server (amd64)
os_arch: amd64
os_family: ubuntu
os_description: ubuntu
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
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
keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false
initrd=/install/initrd.gz -- <Enter>
preseed_cfg: |
## Options to set on the command line
d-i debian-installer/locale string en_US.utf8
d-i console-setup/ask_detect boolean false
d-i console-setup/layout string USA
#d-i netcfg/get_hostname string dummy
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
# Continue without a default route
# Not working , specify a dummy in the DHCP
#d-i netcfg/no_default_route boolean
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 base-installer/kernel/override-image string linux-image-2.6.32-21-generic
# Choices: Dialog, Readline, Gnome, Kde, Editor, Noninteractive
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 regular
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
#http://ubuntu-virginia.ubuntuforums.org/showthread.php?p=9626883
#Message: "write the changes to disk and configure lvm preseed"
#http://serverfault.com/questions/189328/ubuntu-kickstart-installation-using-lvm-waits-for-input
#preseed partman-lvm/confirm_nooverwrite 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
## minimum is ssh and ntp
# Individual additional packages to install
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
#d-i apt-setup/use_mirror boolean true
#d-i mirror/country string manual
#choose-mirror-bin mirror/protocol string http
#choose-mirror-bin mirror/http/hostname string 192.168.4.150
#choose-mirror-bin mirror/http/directory string /ubuntu
#choose-mirror-bin mirror/suite select maverick
#d-i debian-installer/allow_unauthenticated string true
choose-mirror-bin mirror/http/proxy string