added the possiblity for master machines to survive the jvm. first run creates and installs the master vm subsequent calls fetch the already created master from vm

This commit is contained in:
David Ribeiro Alves 2012-03-05 01:09:13 +00:00
parent 690bc9a4dc
commit d0b4d81f9f
13 changed files with 472 additions and 220 deletions

View File

@ -29,11 +29,12 @@ import java.util.Map;
import javax.inject.Inject;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.Template;
import org.jclouds.domain.Location;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.virtualbox.domain.Master;
import org.jclouds.virtualbox.domain.NodeSpec;
import org.jclouds.virtualbox.domain.YamlImage;
import org.virtualbox_4_1.CleanupMode;
import org.virtualbox_4_1.IMachine;
@ -62,13 +63,13 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
private final Supplier<VirtualBoxManager> manager;
private final Map<Image, YamlImage> images;
private final LoadingCache<Image, IMachine> mastersLoader;
private final Function<IMachine, NodeAndInitialCredentials<IMachine>> cloneCreator;
private final LoadingCache<Image, Master> mastersLoader;
private final Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator;
@Inject
public VirtualBoxComputeServiceAdapter(Supplier<VirtualBoxManager> manager,
Supplier<Map<Image, YamlImage>> imagesMapper, LoadingCache<Image, IMachine> mastersLoader,
Function<IMachine, NodeAndInitialCredentials<IMachine>> cloneCreator) {
Supplier<Map<Image, YamlImage>> imagesMapper, LoadingCache<Image, Master> mastersLoader,
Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator) {
this.manager = checkNotNull(manager, "manager");
this.images = imagesMapper.get();
this.mastersLoader = mastersLoader;
@ -79,8 +80,9 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
public NodeAndInitialCredentials<IMachine> createNodeWithGroupEncodedIntoName(String tag, String name,
Template template) {
try {
IMachine master = mastersLoader.get(template.getImage());
return cloneCreator.apply(master);
Master master = mastersLoader.get(template.getImage());
NodeSpec nodeSpec = NodeSpec.builder().master(master).name(name).tag(tag).template(template).build();
return cloneCreator.apply(nodeSpec);
} catch (Exception e) {
throw new RuntimeException(e);
}

View File

@ -20,9 +20,6 @@
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;
@ -60,16 +57,19 @@ 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.CloneSpec;
import org.jclouds.virtualbox.domain.ExecutionType;
import org.jclouds.virtualbox.domain.IsoSpec;
import org.jclouds.virtualbox.domain.Master;
import org.jclouds.virtualbox.domain.MasterSpec;
import org.jclouds.virtualbox.domain.YamlImage;
import org.jclouds.virtualbox.functions.CloneAndRegisterMachineFromIMachineIfNotAlreadyExists;
import org.jclouds.virtualbox.functions.CreateAndInstallVm;
import org.jclouds.virtualbox.functions.IMachineToHardware;
import org.jclouds.virtualbox.functions.IMachineToImage;
import org.jclouds.virtualbox.functions.IMachineToNodeMetadata;
import org.jclouds.virtualbox.functions.IMachineToSshClient;
import org.jclouds.virtualbox.functions.MasterImages;
import org.jclouds.virtualbox.functions.MastersCache;
import org.jclouds.virtualbox.functions.NodeCreator;
import org.jclouds.virtualbox.functions.YamlImagesFromFileConfig;
import org.jclouds.virtualbox.functions.admin.ImagesToYamlImagesFromYamlDescriptor;
@ -134,14 +134,16 @@ public class VirtualBoxComputeServiceContextModule extends
bind(new TypeLiteral<Supplier<String>>() {
}).to((Class) YamlImagesFromFileConfig.class);
// the master machines cache
bind(new TypeLiteral<LoadingCache<Image, IMachine>>() {
}).to((Class) MasterImages.class);
bind(new TypeLiteral<LoadingCache<Image, Master>>() {
}).to((Class) MastersCache.class);
// the master creating function
bind(new TypeLiteral<Function<MasterSpec, IMachine>>() {
}).to((Class) CreateAndInstallVm.class);
// the machine cloning function
bind(new TypeLiteral<Function<IMachine, NodeAndInitialCredentials<IMachine>>>() {
}).to((Class) NodeCreator.class);
bind(new TypeLiteral<Function<CloneSpec, IMachine>>() {
}).to((Class) CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.class);
// for byon
bind(new TypeLiteral<Function<URI, InputStream>>() {

View File

@ -19,10 +19,12 @@
package org.jclouds.virtualbox.domain;
import com.google.common.base.Objects;
import static com.google.common.base.Preconditions.checkNotNull;
import org.virtualbox_4_1.IMachine;
import com.google.common.base.Objects;
/**
* A complete specification of a "clone" node with networking setup
* and the physical machine specification.
@ -31,6 +33,8 @@ public class CloneSpec {
private final VmSpec vmSpec;
private final NetworkSpec networkSpec;
private final IMachine master;
private final boolean isLinked;
public static Builder builder() {
return new Builder();
@ -40,6 +44,8 @@ public class CloneSpec {
private VmSpec vmSpec;
private NetworkSpec networkSpec;
private IMachine master;
private boolean isLinked;
public Builder vm(VmSpec vmSpec) {
this.vmSpec = vmSpec;
@ -50,18 +56,31 @@ public class CloneSpec {
this.networkSpec = networkSpec;
return this;
}
public Builder master(IMachine master){
this.master = master;
return this;
}
public Builder linked(boolean isLinked){
this.isLinked = isLinked;
return this;
}
public CloneSpec build() {
return new CloneSpec(vmSpec, networkSpec);
return new CloneSpec(vmSpec, networkSpec, master ,isLinked);
}
}
public CloneSpec(VmSpec vmSpec, NetworkSpec networkSpec) {
public CloneSpec(VmSpec vmSpec, NetworkSpec networkSpec, IMachine master, boolean isLinked) {
checkNotNull(vmSpec, "vmSpec");
checkNotNull(networkSpec, "networkSpec");
checkNotNull(master, "master");
this.vmSpec = vmSpec;
this.networkSpec = networkSpec;
this.master = master;
this.isLinked = isLinked;
}
public VmSpec getVmSpec() {
@ -71,6 +90,14 @@ public class CloneSpec {
public NetworkSpec getNetworkSpec() {
return networkSpec;
}
public IMachine getMaster() {
return master;
}
public boolean isLinked() {
return isLinked;
}
@Override
public boolean equals(Object o) {

View File

@ -0,0 +1,67 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.virtualbox.domain;
import org.virtualbox_4_1.IMachine;
public class Master {
private final IMachine machine;
private final MasterSpec spec;
public static Builder builder() {
return new Builder();
}
public static class Builder {
private IMachine machine;
private MasterSpec spec;
public Builder machine(IMachine machine){
this.machine = machine;
return this;
}
public Builder spec(MasterSpec spec){
this.spec = spec;
return this;
}
public Master build(){
return new Master(machine,spec);
}
}
private Master(IMachine machine, MasterSpec spec) {
super();
this.machine = machine;
this.spec = spec;
}
public IMachine getMachine() {
return machine;
}
public MasterSpec getSpec() {
return spec;
}
}

View File

@ -64,7 +64,7 @@ public class MasterSpec {
}
public MasterSpec(VmSpec vmSpec, IsoSpec isoSpec, NetworkSpec networkSpec) {
private MasterSpec(VmSpec vmSpec, IsoSpec isoSpec, NetworkSpec networkSpec) {
checkNotNull(vmSpec, "vmSpec");
checkNotNull(isoSpec, "isoSpec");
checkNotNull(networkSpec, "networkSpec");

View File

@ -0,0 +1,92 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.virtualbox.domain;
import org.jclouds.compute.domain.Template;
public class NodeSpec {
private final Master master;
private final String name;
private final String tag;
private final Template template;
public static Builder builder() {
return new Builder();
}
public static class Builder {
private Master master;
private String name;
private String tag;
private Template template;
public Builder master(Master master) {
this.master = master;
return this;
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder tag(String tag) {
this.tag = tag;
return this;
}
public Builder template(Template template) {
this.template = template;
return this;
}
public NodeSpec build() {
return new NodeSpec(master, name, tag, template);
}
}
private NodeSpec(Master master, String name, String tag, Template template) {
super();
this.master = master;
this.name = name;
this.tag = tag;
this.template = template;
}
public Master getMaster() {
return master;
}
public String getName() {
return name;
}
public String getTag() {
return tag;
}
public Template getTemplate() {
return template;
}
}

View File

@ -52,7 +52,7 @@ import com.google.inject.Inject;
* @author Andrea Turli
*/
public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements
Function<IMachine, IMachine> {
Function<CloneSpec, IMachine> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
@ -60,24 +60,20 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements
private final Supplier<VirtualBoxManager> manager;
private final String workingDir;
private final CloneSpec cloneSpec;
private final boolean isLinkedClone;
private final MachineUtils machineUtils;
@Inject
public CloneAndRegisterMachineFromIMachineIfNotAlreadyExists(
Supplier<VirtualBoxManager> manager,
@Named(VirtualBoxConstants.VIRTUALBOX_WORKINGDIR) String workingDir,
CloneSpec cloneSpec, boolean isLinkedClone, MachineUtils machineUtils) {
MachineUtils machineUtils) {
this.manager = manager;
this.workingDir = workingDir;
this.cloneSpec = cloneSpec;
this.isLinkedClone = isLinkedClone;
this.machineUtils = machineUtils;
}
@Override
public IMachine apply(@Nullable IMachine master) {
public IMachine apply(CloneSpec cloneSpec) {
VmSpec vmSpec = cloneSpec.getVmSpec();
try {
manager.get().getVBox().findMachine(vmSpec.getVmName());
@ -85,7 +81,7 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements
+ " is already registered.");
} catch (VBoxException e) {
if (machineNotFoundException(e))
return cloneMachine(vmSpec, master);
return cloneMachine(cloneSpec);
else
throw e;
}
@ -98,7 +94,10 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements
"Could not find a registered machine with UUID {");
}
private IMachine cloneMachine(VmSpec vmSpec, IMachine master) {
private IMachine cloneMachine(CloneSpec cloneSpec) {
VmSpec vmSpec = cloneSpec.getVmSpec();
boolean isLinkedClone = cloneSpec.isLinked();
IMachine master = cloneSpec.getMaster();
String settingsFile = manager.get().getVBox()
.composeMachineFilename(vmSpec.getVmName(), workingDir);
IMachine clonedMachine = manager

View File

@ -53,7 +53,6 @@ import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;

View File

@ -20,6 +20,7 @@
package org.jclouds.virtualbox.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.virtualbox.util.MachineUtils.machineNotFoundException;
import java.io.File;
import java.util.Set;
@ -93,11 +94,6 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExists implements Functi
}
}
private boolean machineNotFoundException(VBoxException e) {
return e.getMessage().contains("VirtualBox error: Could not find a registered machine named ") ||
e.getMessage().contains("Could not find a registered machine with UUID {");
}
private IMachine createMachine(IVirtualBox vBox, MasterSpec machineSpec) {
VmSpec vmSpec = machineSpec.getVmSpec();
String settingsFile = vBox.composeMachineFilename(vmSpec.getVmName(), workingDir);

View File

@ -25,6 +25,7 @@ import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAU
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_WORKINGDIR;
import static org.jclouds.virtualbox.util.MachineUtils.machineNotFoundException;
import java.io.File;
import java.util.Map;
@ -38,6 +39,7 @@ import org.jclouds.Constants;
import org.jclouds.compute.domain.Image;
import org.jclouds.virtualbox.domain.HardDisk;
import org.jclouds.virtualbox.domain.IsoSpec;
import org.jclouds.virtualbox.domain.Master;
import org.jclouds.virtualbox.domain.MasterSpec;
import org.jclouds.virtualbox.domain.NetworkAdapter;
import org.jclouds.virtualbox.domain.NetworkInterfaceCard;
@ -49,6 +51,8 @@ import org.virtualbox_4_1.CleanupMode;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.NetworkAttachmentType;
import org.virtualbox_4_1.StorageBus;
import org.virtualbox_4_1.VBoxException;
import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
@ -63,25 +67,28 @@ import com.google.common.collect.Maps;
* @author dralves
*
*/
public class MasterImages extends AbstractLoadingCache<Image, IMachine> {
public class MastersCache extends AbstractLoadingCache<Image, Master> {
private final Map<String, IMachine> masters = Maps.newHashMap();
private final Function<MasterSpec, IMachine> mastersLoader;
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 adminDisk;
private final String guestAdditionsIso;
private final String installationKeySequence;
private final String isosDir;
private Supplier<VirtualBoxManager> manager;
@Inject
public MasterImages(@Named(Constants.PROPERTY_BUILD_VERSION) String version,
public MastersCache(@Named(Constants.PROPERTY_BUILD_VERSION) String version,
@Named(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE) String installationKeySequence,
@Named(VIRTUALBOX_WORKINGDIR) String workingDir, Function<MasterSpec, IMachine> masterLoader,
Supplier<Map<Image, YamlImage>> yamlMapper) {
Supplier<Map<Image, YamlImage>> yamlMapper, Supplier<VirtualBoxManager> manager) {
checkNotNull(version, "version");
checkNotNull(installationKeySequence, "installationKeySequence");
this.mastersLoader = masterLoader;
checkNotNull(manager, "vboxmanager");
this.manager = manager;
this.masterCreatorAndInstaller = masterLoader;
this.installationKeySequence = installationKeySequence;
this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR : workingDir;
File wdFile = new File(this.workingDir);
@ -100,13 +107,12 @@ public class MasterImages extends AbstractLoadingCache<Image, IMachine> {
}
@Override
public IMachine get(Image key) throws ExecutionException {
public Master get(Image key) throws ExecutionException {
// check if we have loaded this machine before
if (masters.containsKey(key.getId())) {
return masters.get(key);
}
checkNotNull(key, "key");
// the yaml image
YamlImage yamlImage = imageMapping.get(key.getId());
@ -124,15 +130,14 @@ public class MasterImages extends AbstractLoadingCache<Image, IMachine> {
VmSpec vmSpecification = VmSpec.builder().id(yamlImage.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", 2222, "", 22).build();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard
.builder().addNetworkAdapter(networkAdapter).build();
NetworkSpec networkSpec = NetworkSpec.builder()
.addNIC(0L, networkInterfaceCard).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(0L, networkInterfaceCard).build();
MasterSpec masterSpec = MasterSpec
.builder()
@ -140,12 +145,25 @@ public class MasterImages extends AbstractLoadingCache<Image, IMachine> {
.iso(
IsoSpec.builder().sourcePath(localIsoUrl)
.installationScript(installationKeySequence.replace("HOSTNAME", vmSpecification.getVmName())).build())
.network(networkSpec)
.build();
.network(networkSpec).build();
IMachine masterMachine;
// try and find a master machine in vbox
try {
masterMachine = manager.get().getVBox().findMachine(masterSpec.getVmSpec().getVmId());
} catch (VBoxException e) {
if (machineNotFoundException(e))
masterMachine = masterCreatorAndInstaller.apply(masterSpec);
else
throw e;
}
IMachine masterMachine = mastersLoader.apply(masterSpec);
masters.put(key.getId(), masterMachine);
return masterMachine;
Master master = Master.builder().machine(masterMachine).spec(masterSpec).build();
masters.put(key.getId(), master);
return master;
}
private String getFilePathOrDownload(String httpUrl) throws ExecutionException {
@ -158,7 +176,7 @@ public class MasterImages extends AbstractLoadingCache<Image, IMachine> {
}
@Override
public IMachine getIfPresent(Image key) {
public Master getIfPresent(Image key) {
if (masters.containsKey(key.getId())) {
return masters.get(key.getId());
}

View File

@ -1,15 +1,60 @@
/**
* 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 javax.inject.Inject;
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
import org.jclouds.virtualbox.domain.CloneSpec;
import org.jclouds.virtualbox.domain.Master;
import org.jclouds.virtualbox.domain.NodeSpec;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
public class NodeCreator implements Function<IMachine, NodeAndInitialCredentials<IMachine>> {
public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials<IMachine>> {
@Override
public NodeAndInitialCredentials<IMachine> apply(IMachine input) {
throw new UnsupportedOperationException();
private final Supplier<VirtualBoxManager> manager;
private final Function<CloneSpec, IMachine> cloner;
@Inject
public NodeCreator(Supplier<VirtualBoxManager> manager, Function<CloneSpec, IMachine> cloner) {
this.manager = manager;
this.cloner = cloner;
}
@Override
public NodeAndInitialCredentials<IMachine> apply(NodeSpec nodeSpec) {
Master master = nodeSpec.getMaster();
if (master.getMachine().getCurrentSnapshot() != null) {
ISession session = manager.get().openMachineSession(master.getMachine());
session.getConsole().deleteSnapshot(master.getMachine().getCurrentSnapshot().getId());
session.unlockMachine();
}
}
}

View File

@ -52,173 +52,172 @@ import com.google.inject.Inject;
/**
* Utilities for executing functions on a VirtualBox machine.
*
*
* @author Adrian Cole, Mattias Holmqvist, Andrea Turli
*/
@Singleton
public class MachineUtils {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final Supplier<VirtualBoxManager> manager;
private final Factory scriptRunner;
private final Supplier<NodeMetadata> host;
private final Supplier<VirtualBoxManager> manager;
private final Factory scriptRunner;
private final Supplier<NodeMetadata> host;
@Inject
public MachineUtils(Supplier<VirtualBoxManager> manager, RunScriptOnNode.Factory scriptRunner, Supplier<NodeMetadata> host) {
super();
this.manager = manager;
this.scriptRunner = scriptRunner;
this.host = host;
}
public ListenableFuture<ExecResponse> runScriptOnNode(NodeMetadata metadata, Statement statement,
RunScriptOptions options) {
return scriptRunner.submit(metadata, statement, options);
}
@Inject
public MachineUtils(Supplier<VirtualBoxManager> manager, RunScriptOnNode.Factory scriptRunner,
Supplier<NodeMetadata> host) {
super();
this.manager = manager;
this.scriptRunner = scriptRunner;
this.host = host;
}
/**
* Locks the machine and executes the given function using the machine
* matching the given id. Since the machine is locked it is possible to
* perform some modifications to the IMachine.
* <p/>
* Unlocks the machine before returning.
*
* @param machineId the id of the machine
* @param function the function to execute
* @return the result from applying the function to the machine.
*/
public <T> T writeLockMachineAndApply(final String machineId, final Function<IMachine, T> function) {
return lockSessionOnMachineAndApply(machineId, LockType.Write,
new Function<ISession, T>() {
public ListenableFuture<ExecResponse> runScriptOnNode(NodeMetadata metadata, Statement statement,
RunScriptOptions options) {
return scriptRunner.submit(metadata, statement, options);
}
@Override
public T apply(ISession session) {
return function.apply(session.getMachine());
}
/**
* Locks the machine and executes the given function using the machine matching the given id. Since the machine is
* locked it is possible to perform some modifications to the IMachine.
* <p/>
* Unlocks the machine before returning.
*
* @param machineId
* the id of the machine
* @param function
* the function to execute
* @return the result from applying the function to the machine.
*/
public <T> T writeLockMachineAndApply(final String machineId, final Function<IMachine, T> function) {
return lockSessionOnMachineAndApply(machineId, LockType.Write, new Function<ISession, T>() {
@Override
public String toString() {
return function.toString();
}
});
}
/**
* Locks the machine and executes the given function using the current
* session. Since the machine is locked it is possible to perform some
* modifications to the IMachine.
* <p/>
* Unlocks the machine before returning.
*
* @param type the kind of lock to use when initially locking the machine.
* @param machineId the id of the machine
* @param function the function to execute
* @return the result from applying the function to the session.
*/
public <T> T lockSessionOnMachineAndApply(String machineId, LockType type, Function<ISession, T> function) {
try {
ISession session = lockSessionOnMachine(type, machineId);
try {
return function.apply(session);
} finally {
session.unlockMachine();
}
} catch (VBoxException e) {
throw new RuntimeException(String.format(
"error applying %s to %s with %s lock: %s", function, machineId,
type, e.getMessage()), e);
@Override
public T apply(ISession session) {
return function.apply(session.getMachine());
}
}
private ISession lockSessionOnMachine(LockType type, String machineId) {
return new MutableMachine(manager, type).apply(machineId);
}
@Override
public String toString() {
return function.toString();
}
private void unlockMachine(final String machineId) {
});
}
/**
* Locks the machine and executes the given function using the current session. Since the machine is locked it is
* possible to perform some modifications to the IMachine.
* <p/>
* Unlocks the machine before returning.
*
* @param type
* the kind of lock to use when initially locking the machine.
* @param machineId
* the id of the machine
* @param function
* the function to execute
* @return the result from applying the function to the session.
*/
public <T> T lockSessionOnMachineAndApply(String machineId, LockType type, Function<ISession, T> function) {
try {
ISession session = lockSessionOnMachine(type, machineId);
try {
return function.apply(session);
} finally {
session.unlockMachine();
}
} catch (VBoxException e) {
throw new RuntimeException(String.format("error applying %s to %s with %s lock: %s", function, machineId, type,
e.getMessage()), e);
}
}
private ISession lockSessionOnMachine(LockType type, String machineId) {
return new MutableMachine(manager, type).apply(machineId);
}
private void unlockMachine(final String machineId) {
IMachine immutableMachine = manager.get().getVBox().findMachine(machineId);
if (immutableMachine.getSessionState().equals(SessionState.Locked)) {
Statement kill = newStatementList(call("default"), findPid(immutableMachine.getSessionPid().toString()), kill());
scriptRunner.create(host.get(), kill, runAsRoot(false).wrapInInitScript(false)).init().call();
}
}
/**
* Unlocks the machine and executes the given function using the machine matching the given id. Since the machine is
* unlocked it is possible to delete the IMachine.
* <p/>
* <p/>
* <h3>Note!</h3> Currently, this can only unlock the machine, if the lock was created in the current session.
*
* @param machineId
* the id of the machine
* @param function
* the function to execute
* @return the result from applying the function to the machine.
*/
public <T> T unlockMachineAndApply(final String machineId, final Function<IMachine, T> function) {
try {
unlockMachine(machineId);
IMachine immutableMachine = manager.get().getVBox().findMachine(machineId);
if (immutableMachine.getSessionState().equals(SessionState.Locked)) {
Statement kill = newStatementList(call("default"),
findPid(immutableMachine.getSessionPid().toString()), kill());
scriptRunner
.create(host.get(), kill,
runAsRoot(false).wrapInInitScript(false)).init().call();
return function.apply(immutableMachine);
} catch (VBoxException e) {
throw new RuntimeException(String.format("error applying %s to %s: %s", function, machineId, e.getMessage()), e);
}
}
/**
* Unlocks the machine and executes the given function, if the machine is registered. Since the machine is unlocked it
* is possible to delete the machine.
* <p/>
*
* @param machineId
* the id of the machine
* @param function
* the function to execute
* @return the result from applying the function to the session.
*/
public <T> T unlockMachineAndApplyOrReturnNullIfNotRegistered(String machineId, Function<IMachine, T> function) {
try {
return unlockMachineAndApply(machineId, function);
} catch (RuntimeException e) {
VBoxException vbex = Throwables2.getFirstThrowableOfType(e, VBoxException.class);
if (vbex != null && vbex.getMessage().indexOf("not find a registered") == -1)
throw e;
return null;
}
}
/**
* @param machineId
* @param function
* @return
*/
public <T> T applyForMachine(final String machineId, final Function<IMachine, T> function) {
final IMachine immutableMachine = manager.get().getVBox().findMachine(machineId);
return new Function<IMachine, T>() {
@Override
public T apply(IMachine machine) {
return function.apply(machine);
}
}
/**
* Unlocks the machine and executes the given function using the machine
* matching the given id. Since the machine is unlocked it is possible to
* delete the IMachine.
* <p/>
* <p/>
* <h3>Note!</h3> Currently, this can only unlock the machine, if the lock
* was created in the current session.
*
* @param machineId the id of the machine
* @param function the function to execute
* @return the result from applying the function to the machine.
*/
public <T> T unlockMachineAndApply(final String machineId, final Function<IMachine, T> function) {
try {
unlockMachine(machineId);
IMachine immutableMachine = manager.get().getVBox().findMachine(machineId);
return function.apply(immutableMachine);
} catch (VBoxException e) {
throw new RuntimeException(String.format(
"error applying %s to %s: %s", function, machineId,
e.getMessage()), e);
@Override
public String toString() {
return function.toString();
}
}
/**
* Unlocks the machine and executes the given function, if the machine is
* registered. Since the machine is unlocked it is possible to delete the
* machine.
* <p/>
*
* @param machineId the id of the machine
* @param function the function to execute
* @return the result from applying the function to the session.
*/
public <T> T unlockMachineAndApplyOrReturnNullIfNotRegistered(String machineId,
Function<IMachine, T> function) {
try {
return unlockMachineAndApply(machineId, function);
} catch (RuntimeException e) {
VBoxException vbex = Throwables2.getFirstThrowableOfType(e,
VBoxException.class);
if (vbex != null
&& vbex.getMessage().indexOf("not find a registered") == -1)
throw e;
return null;
}
}
/**
* @param machineId
* @param function
* @return
*/
public <T> T applyForMachine(final String machineId, final Function<IMachine, T> function) {
final IMachine immutableMachine = manager.get().getVBox().findMachine(machineId);
return new Function<IMachine, T>() {
@Override
public T apply(IMachine machine) {
return function.apply(machine);
}
@Override
public String toString() {
return function.toString();
}
}.apply(immutableMachine);
}
}.apply(immutableMachine);
}
public static boolean machineNotFoundException(VBoxException e) {
return e.getMessage().contains("VirtualBox error: Could not find a registered machine named ")
|| e.getMessage().contains("Could not find a registered machine with UUID {");
}
}

View File

@ -50,8 +50,8 @@ import com.google.inject.Injector;
/**
* @author Andrea Turli
*/
@Test(groups = "live", singleThreaded = true, testName = "CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest")
public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends
@Test(groups = "live", singleThreaded = true, testName = "CloneAndRegisterMachineFromIMachineIfNotAlreadyExistsLiveTest")
public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExistsLiveTest extends
BaseVirtualBoxClientLiveTest {
private static final boolean IS_LINKED_CLONE = true;
@ -61,6 +61,10 @@ public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends
private CleanupMode mode = CleanupMode.Full;
private VmSpec clonedVmSpec;
private NetworkSpec cloneNetworkSpec;
@Override
@BeforeClass(groups = "live")
public void setupClient() {
@ -101,19 +105,20 @@ public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends
NetworkAdapter networkAdapter = NetworkAdapter.builder()
.networkAttachmentType(NetworkAttachmentType.Bridged).build();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard
.builder().addNetworkAdapter(networkAdapter).build();
NetworkSpec networkSpec = NetworkSpec.builder()
this.cloneNetworkSpec = NetworkSpec.builder()
.addNIC(0L, networkInterfaceCard).build();
sourceMachineSpec = MasterSpec.builder().iso(isoSpec).vm(sourceVmSpec)
.network(networkSpec).build();
.network(cloneNetworkSpec).build();
VmSpec clonedVmSpec = VmSpec.builder().id(cloneName).name(cloneName)
this.clonedVmSpec = VmSpec.builder().id(cloneName).name(cloneName)
.memoryMB(512).cleanUpMode(mode).forceOverwrite(true).build();
cloneSpec = CloneSpec.builder().vm(clonedVmSpec).network(networkSpec)
.build();
}
@ -121,7 +126,9 @@ public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends
public void testCloneMachineFromAnotherMachine() throws Exception {
try {
IMachine source = getSourceNode();
CloneSpec cloneSpec = CloneSpec.builder().vm(clonedVmSpec).network(cloneNetworkSpec).master(source)
.linked(IS_LINKED_CLONE)
.build();
if (source.getCurrentSnapshot() != null) {
ISession session = manager.get().openMachineSession(source);
session.getConsole().deleteSnapshot(
@ -130,8 +137,7 @@ public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends
}
IMachine clone = new CloneAndRegisterMachineFromIMachineIfNotAlreadyExists(
manager, workingDir, cloneSpec, IS_LINKED_CLONE,
machineUtils).apply(source);
manager, workingDir,machineUtils).apply(cloneSpec);
assertEquals(clone.getName(), cloneSpec.getVmSpec().getVmName());
} finally {
for (VmSpec spec : ImmutableSet.of(cloneSpec.getVmSpec(),