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;
@ -51,17 +57,30 @@ public class CloneSpec {
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() {
@ -72,6 +91,14 @@ public class CloneSpec {
return networkSpec;
}
public IMachine getMaster() {
return master;
}
public boolean isLinked() {
return isLinked;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

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());
@ -125,14 +131,13 @@ 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)
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();
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 = mastersLoader.apply(masterSpec);
masters.put(key.getId(), masterMachine);
return masterMachine;
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;
}
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

@ -68,7 +68,8 @@ public class MachineUtils {
private final Supplier<NodeMetadata> host;
@Inject
public MachineUtils(Supplier<VirtualBoxManager> manager, RunScriptOnNode.Factory scriptRunner, Supplier<NodeMetadata> host) {
public MachineUtils(Supplier<VirtualBoxManager> manager, RunScriptOnNode.Factory scriptRunner,
Supplier<NodeMetadata> host) {
super();
this.manager = manager;
this.scriptRunner = scriptRunner;
@ -81,19 +82,19 @@ public class MachineUtils {
}
/**
* 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.
* 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
* @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>() {
return lockSessionOnMachineAndApply(machineId, LockType.Write, new Function<ISession, T>() {
@Override
public T apply(ISession session) {
@ -109,15 +110,17 @@ public class MachineUtils {
}
/**
* 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.
* 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
* @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) {
@ -129,9 +132,8 @@ public class MachineUtils {
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);
throw new RuntimeException(String.format("error applying %s to %s with %s lock: %s", function, machineId, type,
e.getMessage()), e);
}
}
@ -142,25 +144,22 @@ public class MachineUtils {
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();
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.
* 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.
* <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
* @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) {
@ -171,31 +170,27 @@ public class MachineUtils {
return function.apply(immutableMachine);
} catch (VBoxException e) {
throw new RuntimeException(String.format(
"error applying %s to %s: %s", function, machineId,
e.getMessage()), 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.
* 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
* @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) {
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)
VBoxException vbex = Throwables2.getFirstThrowableOfType(e, VBoxException.class);
if (vbex != null && vbex.getMessage().indexOf("not find a registered") == -1)
throw e;
return null;
}
@ -221,4 +216,8 @@ public class MachineUtils {
}.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();
VmSpec clonedVmSpec = VmSpec.builder().id(cloneName).name(cloneName)
sourceMachineSpec = MasterSpec.builder().iso(isoSpec).vm(sourceVmSpec)
.network(cloneNetworkSpec).build();
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(),