mirror of https://github.com/apache/jclouds.git
adapter creates the master image. cloning next
This commit is contained in:
parent
406c6a9fc4
commit
690bc9a4dc
|
@ -19,7 +19,7 @@
|
|||
|
||||
package org.jclouds.virtualbox;
|
||||
|
||||
import static org.jclouds.Constants.PROPERTY_API_VERSION;
|
||||
import static org.jclouds.Constants.*;
|
||||
import static org.jclouds.Constants.PROPERTY_BUILD_VERSION;
|
||||
import static org.jclouds.Constants.PROPERTY_CREDENTIAL;
|
||||
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
|
||||
|
@ -30,7 +30,7 @@ import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAU
|
|||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGES_DESCRIPTOR;
|
||||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
|
||||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_PRECONFIGURATION_URL;
|
||||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_WORKINGDIR;
|
||||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Properties;
|
||||
|
@ -58,6 +58,7 @@ public class VirtualBoxPropertiesBuilder extends PropertiesBuilder {
|
|||
properties.put(PROPERTY_ENDPOINT, "http://localhost:18083/");
|
||||
// later version not in maven, yet
|
||||
properties.put(PROPERTY_API_VERSION, "4.1.4");
|
||||
|
||||
properties.put(PROPERTY_BUILD_VERSION, "4.1.8r75467");
|
||||
properties.put(PROPERTY_IDENTITY, "administrator");
|
||||
properties.put(PROPERTY_CREDENTIAL, "12345");
|
||||
|
|
|
@ -29,13 +29,12 @@ import javax.annotation.Resource;
|
|||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.compute.ComputeServiceContext;
|
||||
import org.jclouds.compute.domain.ExecResponse;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.options.RunScriptOptions;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.ssh.SshClient;
|
||||
import org.jclouds.virtualbox.Host;
|
||||
import org.jclouds.virtualbox.Preconfiguration;
|
||||
import org.jclouds.virtualbox.domain.ExecutionType;
|
||||
import org.jclouds.virtualbox.domain.IsoSpec;
|
||||
|
@ -67,25 +66,23 @@ public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
|
|||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final ComputeServiceContext context;
|
||||
private final Supplier<VirtualBoxManager> manager;
|
||||
private final CreateAndRegisterMachineFromIsoIfNotAlreadyExists createAndRegisterMachineFromIsoIfNotAlreadyExists;
|
||||
|
||||
private final GuestAdditionsInstaller guestAdditionsInstaller;
|
||||
private final Predicate<SshClient> sshResponds;
|
||||
private final ExecutionType executionType;
|
||||
|
||||
private LoadingCache<IsoSpec, URI> preConfiguration;
|
||||
|
||||
private final Function<IMachine, SshClient> sshClientForIMachine;
|
||||
|
||||
private final MachineUtils machineUtils;
|
||||
private final IMachineToNodeMetadata imachineToNodeMetadata;
|
||||
|
||||
@Inject
|
||||
public CreateAndInstallVm(@Host ComputeServiceContext context, Supplier<VirtualBoxManager> manager,
|
||||
public CreateAndInstallVm(Supplier<VirtualBoxManager> manager,
|
||||
CreateAndRegisterMachineFromIsoIfNotAlreadyExists CreateAndRegisterMachineFromIsoIfNotAlreadyExists,
|
||||
GuestAdditionsInstaller guestAdditionsInstaller, IMachineToNodeMetadata imachineToNodeMetadata,
|
||||
Predicate<SshClient> sshResponds, Function<IMachine, SshClient> sshClientForIMachine,
|
||||
ExecutionType executionType, MachineUtils machineUtils, @Preconfiguration LoadingCache<IsoSpec, URI> preConfiguration) {
|
||||
this.context = context;
|
||||
ExecutionType executionType, MachineUtils machineUtils,
|
||||
@Preconfiguration LoadingCache<IsoSpec, URI> preConfiguration) {
|
||||
this.manager = manager;
|
||||
this.createAndRegisterMachineFromIsoIfNotAlreadyExists = CreateAndRegisterMachineFromIsoIfNotAlreadyExists;
|
||||
this.sshResponds = sshResponds;
|
||||
|
@ -93,6 +90,8 @@ public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
|
|||
this.executionType = executionType;
|
||||
this.machineUtils = machineUtils;
|
||||
this.preConfiguration = preConfiguration;
|
||||
this.guestAdditionsInstaller = guestAdditionsInstaller;
|
||||
this.imachineToNodeMetadata = imachineToNodeMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -102,7 +101,7 @@ public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
|
|||
IsoSpec isoSpec = masterSpec.getIsoSpec();
|
||||
String vmName = vmSpec.getVmName();
|
||||
|
||||
final IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists.apply(masterSpec);
|
||||
IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists.apply(masterSpec);
|
||||
|
||||
// Launch machine and wait for it to come online
|
||||
ensureMachineIsLaunched(vmName);
|
||||
|
@ -118,22 +117,26 @@ public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
|
|||
checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh", vmName);
|
||||
|
||||
logger.debug(">> awaiting installation of guest additions on vm: %s", vmName);
|
||||
checkState(new GuestAdditionsInstaller(context).apply(vmName));
|
||||
|
||||
checkState(guestAdditionsInstaller.apply(vm));
|
||||
|
||||
logger.debug(">> awaiting post-installation actions on vm: %s", vmName);
|
||||
ListenableFuture<ExecResponse> execFuture = context.getComputeService().submitScriptOnNode(vmName,
|
||||
call("cleanupUdevIfNeeded"), RunScriptOptions.NONE);
|
||||
|
||||
NodeMetadata vmMetadata = imachineToNodeMetadata.apply(vm);
|
||||
ListenableFuture<ExecResponse> execFuture = machineUtils.runScriptOnNode(vmMetadata, call("cleanupUdevIfNeeded"),
|
||||
RunScriptOptions.NONE);
|
||||
ExecResponse execResponse = Futures.getUnchecked(execFuture);
|
||||
checkState(execResponse.getExitCode() == 0);
|
||||
|
||||
logger.debug("<< installation of image complete. Powering down node(%s)", vmName);
|
||||
|
||||
ensureMachineHasPowerDown(vmName);
|
||||
return vm;
|
||||
}
|
||||
|
||||
private void configureOsInstallationWithKeyboardSequence(String vmName, String installationKeySequence) {
|
||||
Iterable<List<Integer>> scancodelist =
|
||||
transform(Splitter.on(" ").split(installationKeySequence), new StringToKeyCode());
|
||||
Iterable<List<Integer>> scancodelist = transform(Splitter.on(" ").split(installationKeySequence),
|
||||
new StringToKeyCode());
|
||||
|
||||
for (List<Integer> scancodes : scancodelist) {
|
||||
machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, new SendScancodes(scancodes));
|
||||
|
@ -146,7 +149,8 @@ public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
|
|||
* @param vmName
|
||||
*/
|
||||
private void ensureMachineHasPowerDown(String vmName) {
|
||||
while(!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.POWERED_OFF)) {
|
||||
while (!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.POWERED_OFF)) {
|
||||
try {
|
||||
machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, new Function<ISession, Void>() {
|
||||
@Override
|
||||
public Void apply(ISession session) {
|
||||
|
@ -155,10 +159,15 @@ public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
|
|||
return null;
|
||||
}
|
||||
});
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Throwables.propagate(e);
|
||||
} catch (RuntimeException e) {
|
||||
// sometimes the machine might be powered of between the while test and the call to lockSessionOnMachineAndApply
|
||||
if (e.getMessage().contains("Invalid machine state: PoweredOff")){
|
||||
return;
|
||||
} else if(e.getMessage().contains("VirtualBox error: The object is not ready")){
|
||||
continue;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,8 @@ public class IMachineToImage implements Function<IMachine, Image> {
|
|||
OperatingSystem os = OperatingSystem.builder().description(guestOSType.getDescription()).family(family)
|
||||
.version(version).is64Bit(guestOSType.getIs64Bit()).build();
|
||||
|
||||
return new ImageBuilder().id("" + from.getId()).description(from.getDescription()).operatingSystem(os).build();
|
||||
return new ImageBuilder().id("" + from.getId()).name(from.getName()).description(from.getDescription())
|
||||
.operatingSystem(os).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,40 +4,48 @@ import javax.annotation.Resource;
|
|||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.compute.ComputeServiceContext;
|
||||
import org.jclouds.compute.domain.ExecResponse;
|
||||
import org.jclouds.compute.options.RunScriptOptions;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.virtualbox.functions.IMachineToNodeMetadata;
|
||||
import org.jclouds.virtualbox.statements.InstallGuestAdditions;
|
||||
import org.jclouds.virtualbox.util.MachineUtils;
|
||||
import org.virtualbox_4_1.IMachine;
|
||||
import org.virtualbox_4_1.VirtualBoxManager;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
@Singleton
|
||||
public class GuestAdditionsInstaller implements Predicate<String> {
|
||||
public class GuestAdditionsInstaller implements Predicate<IMachine> {
|
||||
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final ComputeServiceContext vboxHostContext;
|
||||
private String vboxVersion;
|
||||
private final IMachineToNodeMetadata imachineToNodeMetadata;
|
||||
private final MachineUtils machineUtils;
|
||||
private final Supplier<VirtualBoxManager> manager;
|
||||
|
||||
@Inject
|
||||
public GuestAdditionsInstaller(ComputeServiceContext vboxHostContext) {
|
||||
this.vboxHostContext = vboxHostContext;
|
||||
public GuestAdditionsInstaller(Supplier<VirtualBoxManager> manager, MachineUtils machineUtils,
|
||||
IMachineToNodeMetadata imachineToNodeMetadata) {
|
||||
this.machineUtils = machineUtils;
|
||||
this.imachineToNodeMetadata = imachineToNodeMetadata;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(String vmName) {
|
||||
vboxVersion = Iterables.get(Splitter.on('r').split(vboxHostContext.getProviderSpecificContext().getBuildVersion()),
|
||||
0);
|
||||
ListenableFuture<ExecResponse> execFuture = vboxHostContext.getComputeService().submitScriptOnNode(vmName,
|
||||
public boolean apply(IMachine machine) {
|
||||
String vboxVersion = Iterables.get(Splitter.on('r').split(manager.get().getVBox().getVersion()), 0);
|
||||
System.out.println("VERSION: " + vboxVersion);
|
||||
ListenableFuture<ExecResponse> execFuture = machineUtils.runScriptOnNode(imachineToNodeMetadata.apply(machine),
|
||||
new InstallGuestAdditions(vboxVersion), RunScriptOptions.NONE);
|
||||
ExecResponse execResponse = Futures.getUnchecked(execFuture);
|
||||
return execResponse == null ? false : execResponse.getExitStatus() == 0;
|
||||
|
|
|
@ -30,7 +30,9 @@ import javax.inject.Singleton;
|
|||
|
||||
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.options.RunScriptOptions;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
|
@ -45,6 +47,7 @@ import org.virtualbox_4_1.VirtualBoxManager;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
|
@ -72,6 +75,11 @@ public class MachineUtils {
|
|||
this.host = host;
|
||||
}
|
||||
|
||||
public ListenableFuture<ExecResponse> runScriptOnNode(NodeMetadata metadata, Statement statement,
|
||||
RunScriptOptions options) {
|
||||
return scriptRunner.submit(metadata, statement, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks the machine and executes the given function using the machine
|
||||
* matching the given id. Since the machine is locked it is possible to
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.jclouds.virtualbox;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
|
@ -42,7 +43,11 @@ import org.jclouds.virtualbox.util.MachineUtils;
|
|||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
import org.virtualbox_4_1.IProgress;
|
||||
import org.virtualbox_4_1.ISession;
|
||||
import org.virtualbox_4_1.LockType;
|
||||
import org.virtualbox_4_1.VirtualBoxManager;
|
||||
import org.virtualbox_4_1.jaxws.MachineState;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Splitter;
|
||||
|
@ -75,6 +80,7 @@ public class BaseVirtualBoxClientLiveTest extends BaseVersionedServiceLiveTest {
|
|||
protected String guestAdditionsIso;
|
||||
protected String adminDisk;
|
||||
protected String workingDir;
|
||||
protected String isosDir;
|
||||
protected Supplier<NodeMetadata> host;
|
||||
|
||||
@Override
|
||||
|
@ -122,10 +128,14 @@ public class BaseVirtualBoxClientLiveTest extends BaseVersionedServiceLiveTest {
|
|||
hostModule), overrides);
|
||||
Function<String, String> configProperties = context.utils().injector()
|
||||
.getInstance(ValueOfConfigurationKeyOrNull.class);
|
||||
imageId = configProperties
|
||||
.apply(ComputeServiceConstants.PROPERTY_IMAGE_ID);
|
||||
imageId = "ubuntu-11.04-server-i386";
|
||||
workingDir = configProperties
|
||||
.apply(VirtualBoxConstants.VIRTUALBOX_WORKINGDIR);
|
||||
isosDir = workingDir+File.separator+"isos";
|
||||
File isosDirFile = new File(isosDir);
|
||||
if(!isosDirFile.exists()){
|
||||
isosDirFile.mkdirs();
|
||||
}
|
||||
host = context.utils().injector()
|
||||
.getInstance(Key.get(new TypeLiteral<Supplier<NodeMetadata>>() {
|
||||
}));
|
||||
|
@ -146,9 +156,9 @@ public class BaseVirtualBoxClientLiveTest extends BaseVersionedServiceLiveTest {
|
|||
Splitter.on('r').split(
|
||||
context.getProviderSpecificContext().getBuildVersion()), 0);
|
||||
adminDisk = workingDir + "/testadmin.vdi";
|
||||
operatingSystemIso = String.format("%s/%s.iso", workingDir, imageId);
|
||||
operatingSystemIso = String.format("%s/%s.iso", isosDir, imageId);
|
||||
guestAdditionsIso = String.format("%s/VBoxGuestAdditions_%s.iso",
|
||||
workingDir, hostVersion);
|
||||
isosDir, hostVersion);
|
||||
}
|
||||
|
||||
protected void undoVm(VmSpec vmSpecification) {
|
||||
|
@ -157,6 +167,30 @@ public class BaseVirtualBoxClientLiveTest extends BaseVersionedServiceLiveTest {
|
|||
new UnregisterMachineIfExistsAndDeleteItsMedia(vmSpecification));
|
||||
}
|
||||
|
||||
protected void ensureMachineHasPowerDown(String vmName) {
|
||||
while (!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.POWERED_OFF)) {
|
||||
try {
|
||||
machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, new Function<ISession, Void>() {
|
||||
@Override
|
||||
public Void apply(ISession session) {
|
||||
IProgress powerDownProgress = session.getConsole().powerDown();
|
||||
powerDownProgress.waitForCompletion(-1);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (RuntimeException e) {
|
||||
// sometimes the machine might be powered of between the while test and the call to lockSessionOnMachineAndApply
|
||||
if (e.getMessage().contains("Invalid machine state: PoweredOff")){
|
||||
return;
|
||||
} else if(e.getMessage().contains("VirtualBox error: The object is not ready")){
|
||||
continue;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass(groups = "live")
|
||||
protected void tearDown() throws Exception {
|
||||
if (context != null)
|
||||
|
|
|
@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkState;
|
|||
import static com.google.common.base.Predicates.equalTo;
|
||||
import static com.google.common.collect.Iterables.any;
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
|
||||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
@ -88,12 +89,13 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest {
|
|||
private Injector injector;
|
||||
private Function<IMachine, SshClient> sshClientForIMachine;
|
||||
private Predicate<SshClient> sshResponds;
|
||||
private String vmName;
|
||||
|
||||
@Override
|
||||
@BeforeClass(groups = "live")
|
||||
public void setupClient() {
|
||||
super.setupClient();
|
||||
String vmName = VIRTUALBOX_IMAGE_PREFIX
|
||||
this.vmName = VIRTUALBOX_IMAGE_PREFIX
|
||||
+ CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass()
|
||||
.getSimpleName());
|
||||
|
||||
|
@ -136,16 +138,12 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest {
|
|||
undoVm(vmSpecification);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateImageMachineFromIso() throws Exception {
|
||||
IMachine imageMachine = getVmWithGuestAdditionsInstalled();
|
||||
|
||||
IMachineToImage iMachineToImage = new IMachineToImage(manager, map);
|
||||
Image newImage = iMachineToImage.apply(imageMachine);
|
||||
// TODO add the description to the cache of the images or serialize to
|
||||
// YAML the image desc
|
||||
Set<? extends Image> images = context.getComputeService().listImages();
|
||||
Iterable<String> imageIds = transform(images, extractId());
|
||||
assertTrue(any(imageIds, equalTo(newImage.getId())));
|
||||
assertEquals(vmName,newImage.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -212,27 +210,6 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest {
|
|||
}
|
||||
}
|
||||
|
||||
private void ensureMachineHasPowerDown(String vmName) {
|
||||
while (!manager.get().getVBox().findMachine(vmName).getState()
|
||||
.equals(MachineState.POWERED_OFF)) {
|
||||
machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared,
|
||||
new Function<ISession, Void>() {
|
||||
@Override
|
||||
public Void apply(ISession session) {
|
||||
IProgress powerDownProgress = session.getConsole()
|
||||
.powerDown();
|
||||
powerDownProgress.waitForCompletion(-1);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@AfterClass(groups = "live")
|
||||
protected void tearDown() throws Exception {
|
||||
|
|
|
@ -144,16 +144,4 @@ public class GuestAdditionsInstallerLiveTest extends
|
|||
}
|
||||
}
|
||||
|
||||
private void ensureMachineHasPowerDown(String vmName) {
|
||||
machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared,
|
||||
new Function<ISession, Void>() {
|
||||
@Override
|
||||
public Void apply(ISession session) {
|
||||
IProgress powerDownProgress = session.getConsole()
|
||||
.powerDown();
|
||||
powerDownProgress.waitForCompletion(-1);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue