mirror of https://github.com/apache/jclouds.git
added a computeservicecontext provider for the vbox host (byon)
This commit is contained in:
parent
e00181d74e
commit
960e6f8e0a
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.inject.Qualifier;
|
||||
|
||||
/**
|
||||
* Signals the annotated target pertains to the vbox host and not to one of the nodes.
|
||||
*
|
||||
* @author dralves
|
||||
*
|
||||
*/
|
||||
@Retention(value = RetentionPolicy.RUNTIME)
|
||||
@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
|
||||
@Qualifier
|
||||
public @interface Host {
|
||||
|
||||
}
|
|
@ -20,6 +20,9 @@
|
|||
package org.jclouds.virtualbox.config;
|
||||
|
||||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_PRECONFIGURATION_URL;
|
||||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_PROVIDER;
|
||||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_WEBSERVER_CREDENTIAL;
|
||||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_WEBSERVER_IDENTITY;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
|
@ -32,10 +35,13 @@ import javax.inject.Singleton;
|
|||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.jclouds.byon.Node;
|
||||
import org.jclouds.byon.config.CacheNodeStoreModule;
|
||||
import org.jclouds.byon.functions.NodeToNodeMetadata;
|
||||
import org.jclouds.byon.suppliers.SupplyFromProviderURIOrNodesProperty;
|
||||
import org.jclouds.compute.ComputeServiceAdapter;
|
||||
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
|
||||
import org.jclouds.compute.ComputeServiceContext;
|
||||
import org.jclouds.compute.ComputeServiceContextFactory;
|
||||
import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
|
||||
import org.jclouds.compute.domain.Hardware;
|
||||
import org.jclouds.compute.domain.HardwareBuilder;
|
||||
|
@ -47,8 +53,11 @@ import org.jclouds.compute.domain.TemplateBuilder;
|
|||
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.functions.IdentityFunction;
|
||||
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
|
||||
import org.jclouds.predicates.RetryablePredicate;
|
||||
import org.jclouds.ssh.SshClient;
|
||||
import org.jclouds.sshj.config.SshjSshClientModule;
|
||||
import org.jclouds.virtualbox.Host;
|
||||
import org.jclouds.virtualbox.Preconfiguration;
|
||||
import org.jclouds.virtualbox.compute.VirtualBoxComputeServiceAdapter;
|
||||
import org.jclouds.virtualbox.domain.ExecutionType;
|
||||
|
@ -82,7 +91,9 @@ import com.google.common.cache.CacheBuilder;
|
|||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
|
@ -150,6 +161,23 @@ public class VirtualBoxComputeServiceContextModule extends
|
|||
return CacheBuilder.newBuilder().build(cacheLoader);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Host
|
||||
@Singleton
|
||||
protected ComputeServiceContext provideHostController() {
|
||||
String provider = "byon";
|
||||
String identity = "";
|
||||
String credential = "";
|
||||
CacheNodeStoreModule hostModule = new CacheNodeStoreModule(ImmutableMap.of(
|
||||
"host",
|
||||
Node.builder().id("host").name("host installing virtualbox").hostname("localhost")
|
||||
.osFamily(OsFamily.LINUX.toString()).osDescription(System.getProperty("os.name"))
|
||||
.osVersion(System.getProperty("os.version")).group("ssh").username(System.getProperty("user.name"))
|
||||
.credentialUrl(URI.create("file://" + System.getProperty("user.home") + "/.ssh/id_rsa")).build()));
|
||||
return new ComputeServiceContextFactory().createContext(provider, identity, credential,
|
||||
ImmutableSet.<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule(), hostModule));
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Server providesJettyServer(@Named(VIRTUALBOX_PRECONFIGURATION_URL) String preconfigurationUrl) {
|
||||
|
|
|
@ -57,5 +57,7 @@ public interface VirtualBoxConstants {
|
|||
|
||||
public static final String VIRTUALBOX_DEFAULT_DIR = System.getProperty("user.home")
|
||||
+ File.separator +".jclouds-vbox";
|
||||
|
||||
public static final String VIRTUALBOX_PROVIDER = "virtualbox";
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ 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;
|
||||
|
@ -60,96 +61,97 @@ import com.google.inject.Inject;
|
|||
@Singleton
|
||||
public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
|
||||
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final ComputeServiceContext context;
|
||||
private final Supplier<VirtualBoxManager> manager;
|
||||
private final CreateAndRegisterMachineFromIsoIfNotAlreadyExists createAndRegisterMachineFromIsoIfNotAlreadyExists;
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final Predicate<SshClient> sshResponds;
|
||||
private final ExecutionType executionType;
|
||||
private final ComputeServiceContext vboxHostContext;
|
||||
private final Supplier<VirtualBoxManager> manager;
|
||||
private final CreateAndRegisterMachineFromIsoIfNotAlreadyExists createAndRegisterMachineFromIsoIfNotAlreadyExists;
|
||||
|
||||
private LoadingCache<IsoSpec, URI> preConfiguration;
|
||||
private final Predicate<SshClient> sshResponds;
|
||||
private final ExecutionType executionType;
|
||||
|
||||
private final Function<IMachine, SshClient> sshClientForIMachine;
|
||||
private LoadingCache<IsoSpec, URI> preConfiguration;
|
||||
|
||||
private final MachineUtils machineUtils;
|
||||
private final Function<IMachine, SshClient> sshClientForIMachine;
|
||||
|
||||
@Inject
|
||||
public CreateAndInstallVm(ComputeServiceContext context, Supplier<VirtualBoxManager> manager,
|
||||
CreateAndRegisterMachineFromIsoIfNotAlreadyExists CreateAndRegisterMachineFromIsoIfNotAlreadyExists,
|
||||
Predicate<SshClient> sshResponds, Function<IMachine, SshClient> sshClientForIMachine,
|
||||
ExecutionType executionType, MachineUtils machineUtils, @Preconfiguration LoadingCache<IsoSpec, URI> preConfiguration) {
|
||||
this.context = context;
|
||||
this.manager = manager;
|
||||
this.createAndRegisterMachineFromIsoIfNotAlreadyExists = CreateAndRegisterMachineFromIsoIfNotAlreadyExists;
|
||||
this.sshResponds = sshResponds;
|
||||
this.sshClientForIMachine = sshClientForIMachine;
|
||||
this.executionType = executionType;
|
||||
this.machineUtils = machineUtils;
|
||||
this.preConfiguration = preConfiguration;
|
||||
}
|
||||
private final MachineUtils machineUtils;
|
||||
|
||||
@Override
|
||||
public IMachine apply(MasterSpec masterSpec) {
|
||||
@Inject
|
||||
public CreateAndInstallVm(@Host ComputeServiceContext vboxHostContext, Supplier<VirtualBoxManager> manager,
|
||||
CreateAndRegisterMachineFromIsoIfNotAlreadyExists CreateAndRegisterMachineFromIsoIfNotAlreadyExists,
|
||||
Predicate<SshClient> sshResponds, Function<IMachine, SshClient> sshClientForIMachine,
|
||||
ExecutionType executionType, MachineUtils machineUtils,
|
||||
@Preconfiguration LoadingCache<IsoSpec, URI> preConfiguration) {
|
||||
this.vboxHostContext = vboxHostContext;
|
||||
this.manager = manager;
|
||||
this.createAndRegisterMachineFromIsoIfNotAlreadyExists = CreateAndRegisterMachineFromIsoIfNotAlreadyExists;
|
||||
this.sshResponds = sshResponds;
|
||||
this.sshClientForIMachine = sshClientForIMachine;
|
||||
this.executionType = executionType;
|
||||
this.machineUtils = machineUtils;
|
||||
this.preConfiguration = preConfiguration;
|
||||
}
|
||||
|
||||
VmSpec vmSpec = masterSpec.getVmSpec();
|
||||
IsoSpec isoSpec = masterSpec.getIsoSpec();
|
||||
String vmName = vmSpec.getVmName();
|
||||
|
||||
final IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists.apply(masterSpec);
|
||||
@Override
|
||||
public IMachine apply(MasterSpec masterSpec) {
|
||||
|
||||
// Launch machine and wait for it to come online
|
||||
ensureMachineIsLaunched(vmName);
|
||||
|
||||
URI uri = preConfiguration.getUnchecked(isoSpec);
|
||||
String installationKeySequence = isoSpec.getInstallationKeySequence().replace("PRECONFIGURATION_URL",
|
||||
uri.toASCIIString());
|
||||
VmSpec vmSpec = masterSpec.getVmSpec();
|
||||
IsoSpec isoSpec = masterSpec.getIsoSpec();
|
||||
String vmName = vmSpec.getVmName();
|
||||
|
||||
configureOsInstallationWithKeyboardSequence(vmName, installationKeySequence);
|
||||
SshClient client = sshClientForIMachine.apply(vm);
|
||||
logger.debug(">> awaiting installation to finish node(%s)", vmName);
|
||||
final IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists.apply(masterSpec);
|
||||
|
||||
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));
|
||||
|
||||
logger.debug(">> awaiting post-installation actions on vm: %s", vmName);
|
||||
ListenableFuture<ExecResponse> execFuture = context.getComputeService().submitScriptOnNode(vmName,
|
||||
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;
|
||||
}
|
||||
// Launch machine and wait for it to come online
|
||||
ensureMachineIsLaunched(vmName);
|
||||
|
||||
private void configureOsInstallationWithKeyboardSequence(String vmName, String installationKeySequence) {
|
||||
Iterable<List<Integer>> scancodelist =
|
||||
transform(Splitter.on(" ").split(installationKeySequence), new StringToKeyCode());
|
||||
URI uri = preConfiguration.getUnchecked(isoSpec);
|
||||
String installationKeySequence = isoSpec.getInstallationKeySequence().replace("PRECONFIGURATION_URL",
|
||||
uri.toASCIIString());
|
||||
|
||||
for (List<Integer> scancodes : scancodelist) {
|
||||
machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, new SendScancodes(scancodes));
|
||||
configureOsInstallationWithKeyboardSequence(vmName, installationKeySequence);
|
||||
SshClient client = sshClientForIMachine.apply(vm);
|
||||
logger.debug(">> awaiting installation to finish node(%s)", vmName);
|
||||
|
||||
checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh", vmName);
|
||||
|
||||
logger.debug(">> awaiting installation of guest additions on vm: %s", vmName);
|
||||
checkState(new GuestAdditionsInstaller(vboxHostContext).apply(vmName));
|
||||
|
||||
logger.debug(">> awaiting post-installation actions on vm: %s", vmName);
|
||||
ListenableFuture<ExecResponse> execFuture = vboxHostContext.getComputeService().submitScriptOnNode(vmName,
|
||||
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());
|
||||
|
||||
for (List<Integer> scancodes : scancodelist) {
|
||||
machineUtils.lockSessionOnMachineAndApply(vmName, LockType.Shared, new SendScancodes(scancodes));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ensureMachineIsLaunched(String vmName) {
|
||||
machineUtils.applyForMachine(vmName, new LaunchMachineIfNotAlreadyRunning(manager.get(), executionType, ""));
|
||||
}
|
||||
private void ensureMachineIsLaunched(String vmName) {
|
||||
machineUtils.applyForMachine(vmName, new LaunchMachineIfNotAlreadyRunning(manager.get(), executionType, ""));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,25 +21,26 @@ import com.google.inject.Inject;
|
|||
@Singleton
|
||||
public class GuestAdditionsInstaller implements Predicate<String> {
|
||||
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final ComputeServiceContext context;
|
||||
private String vboxVersion;
|
||||
private final ComputeServiceContext vboxHostContext;
|
||||
private String vboxVersion;
|
||||
|
||||
@Inject
|
||||
public GuestAdditionsInstaller(ComputeServiceContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
@Inject
|
||||
public GuestAdditionsInstaller(ComputeServiceContext vboxHostContext) {
|
||||
this.vboxHostContext = vboxHostContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(String vmName) {
|
||||
vboxVersion = Iterables.get(Splitter.on('r').split(context.getProviderSpecificContext().getBuildVersion()), 0);
|
||||
ListenableFuture<ExecResponse> execFuture = context.getComputeService().submitScriptOnNode(vmName,
|
||||
new InstallGuestAdditions(vboxVersion), RunScriptOptions.NONE);
|
||||
ExecResponse execResponse = Futures.getUnchecked(execFuture);
|
||||
return execResponse == null ? false : execResponse.getExitStatus() == 0;
|
||||
}
|
||||
@Override
|
||||
public boolean apply(String vmName) {
|
||||
vboxVersion = Iterables.get(Splitter.on('r').split(vboxHostContext.getProviderSpecificContext().getBuildVersion()),
|
||||
0);
|
||||
ListenableFuture<ExecResponse> execFuture = vboxHostContext.getComputeService().submitScriptOnNode(vmName,
|
||||
new InstallGuestAdditions(vboxVersion), RunScriptOptions.NONE);
|
||||
ExecResponse execResponse = Futures.getUnchecked(execFuture);
|
||||
return execResponse == null ? false : execResponse.getExitStatus() == 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -45,7 +45,9 @@ public class SshResponds implements Predicate<SshClient> {
|
|||
} catch (SshException e) {
|
||||
logger.trace("No response from ssh daemon connecting to %s: %s", client, e.getMessage());
|
||||
} finally {
|
||||
if (client != null) {
|
||||
client.disconnect();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue