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

View File

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

View File

@ -19,10 +19,12 @@
package org.jclouds.virtualbox.domain; package org.jclouds.virtualbox.domain;
import com.google.common.base.Objects;
import static com.google.common.base.Preconditions.checkNotNull; 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 * A complete specification of a "clone" node with networking setup
* and the physical machine specification. * and the physical machine specification.
@ -31,6 +33,8 @@ public class CloneSpec {
private final VmSpec vmSpec; private final VmSpec vmSpec;
private final NetworkSpec networkSpec; private final NetworkSpec networkSpec;
private final IMachine master;
private final boolean isLinked;
public static Builder builder() { public static Builder builder() {
return new Builder(); return new Builder();
@ -40,6 +44,8 @@ public class CloneSpec {
private VmSpec vmSpec; private VmSpec vmSpec;
private NetworkSpec networkSpec; private NetworkSpec networkSpec;
private IMachine master;
private boolean isLinked;
public Builder vm(VmSpec vmSpec) { public Builder vm(VmSpec vmSpec) {
this.vmSpec = vmSpec; this.vmSpec = vmSpec;
@ -51,17 +57,30 @@ public class CloneSpec {
return this; 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() { 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(vmSpec, "vmSpec");
checkNotNull(networkSpec, "networkSpec"); checkNotNull(networkSpec, "networkSpec");
checkNotNull(master, "master");
this.vmSpec = vmSpec; this.vmSpec = vmSpec;
this.networkSpec = networkSpec; this.networkSpec = networkSpec;
this.master = master;
this.isLinked = isLinked;
} }
public VmSpec getVmSpec() { public VmSpec getVmSpec() {
@ -72,6 +91,14 @@ public class CloneSpec {
return networkSpec; return networkSpec;
} }
public IMachine getMaster() {
return master;
}
public boolean isLinked() {
return isLinked;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; 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(vmSpec, "vmSpec");
checkNotNull(isoSpec, "isoSpec"); checkNotNull(isoSpec, "isoSpec");
checkNotNull(networkSpec, "networkSpec"); 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 * @author Andrea Turli
*/ */
public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements
Function<IMachine, IMachine> { Function<CloneSpec, IMachine> {
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
@ -60,24 +60,20 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements
private final Supplier<VirtualBoxManager> manager; private final Supplier<VirtualBoxManager> manager;
private final String workingDir; private final String workingDir;
private final CloneSpec cloneSpec;
private final boolean isLinkedClone;
private final MachineUtils machineUtils; private final MachineUtils machineUtils;
@Inject @Inject
public CloneAndRegisterMachineFromIMachineIfNotAlreadyExists( public CloneAndRegisterMachineFromIMachineIfNotAlreadyExists(
Supplier<VirtualBoxManager> manager, Supplier<VirtualBoxManager> manager,
@Named(VirtualBoxConstants.VIRTUALBOX_WORKINGDIR) String workingDir, @Named(VirtualBoxConstants.VIRTUALBOX_WORKINGDIR) String workingDir,
CloneSpec cloneSpec, boolean isLinkedClone, MachineUtils machineUtils) { MachineUtils machineUtils) {
this.manager = manager; this.manager = manager;
this.workingDir = workingDir; this.workingDir = workingDir;
this.cloneSpec = cloneSpec;
this.isLinkedClone = isLinkedClone;
this.machineUtils = machineUtils; this.machineUtils = machineUtils;
} }
@Override @Override
public IMachine apply(@Nullable IMachine master) { public IMachine apply(CloneSpec cloneSpec) {
VmSpec vmSpec = cloneSpec.getVmSpec(); VmSpec vmSpec = cloneSpec.getVmSpec();
try { try {
manager.get().getVBox().findMachine(vmSpec.getVmName()); manager.get().getVBox().findMachine(vmSpec.getVmName());
@ -85,7 +81,7 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements
+ " is already registered."); + " is already registered.");
} catch (VBoxException e) { } catch (VBoxException e) {
if (machineNotFoundException(e)) if (machineNotFoundException(e))
return cloneMachine(vmSpec, master); return cloneMachine(cloneSpec);
else else
throw e; throw e;
} }
@ -98,7 +94,10 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements
"Could not find a registered machine with UUID {"); "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() String settingsFile = manager.get().getVBox()
.composeMachineFilename(vmSpec.getVmName(), workingDir); .composeMachineFilename(vmSpec.getVmName(), workingDir);
IMachine clonedMachine = manager 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.Predicate;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;

View File

@ -20,6 +20,7 @@
package org.jclouds.virtualbox.functions; package org.jclouds.virtualbox.functions;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.virtualbox.util.MachineUtils.machineNotFoundException;
import java.io.File; import java.io.File;
import java.util.Set; 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) { private IMachine createMachine(IVirtualBox vBox, MasterSpec machineSpec) {
VmSpec vmSpec = machineSpec.getVmSpec(); VmSpec vmSpec = machineSpec.getVmSpec();
String settingsFile = vBox.composeMachineFilename(vmSpec.getVmName(), workingDir); 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_IMAGE_PREFIX;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE; 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.config.VirtualBoxConstants.VIRTUALBOX_WORKINGDIR;
import static org.jclouds.virtualbox.util.MachineUtils.machineNotFoundException;
import java.io.File; import java.io.File;
import java.util.Map; import java.util.Map;
@ -38,6 +39,7 @@ import org.jclouds.Constants;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.virtualbox.domain.HardDisk; import org.jclouds.virtualbox.domain.HardDisk;
import org.jclouds.virtualbox.domain.IsoSpec; import org.jclouds.virtualbox.domain.IsoSpec;
import org.jclouds.virtualbox.domain.Master;
import org.jclouds.virtualbox.domain.MasterSpec; import org.jclouds.virtualbox.domain.MasterSpec;
import org.jclouds.virtualbox.domain.NetworkAdapter; import org.jclouds.virtualbox.domain.NetworkAdapter;
import org.jclouds.virtualbox.domain.NetworkInterfaceCard; 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.IMachine;
import org.virtualbox_4_1.NetworkAttachmentType; import org.virtualbox_4_1.NetworkAttachmentType;
import org.virtualbox_4_1.StorageBus; 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.Function;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
@ -63,25 +67,28 @@ import com.google.common.collect.Maps;
* @author dralves * @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 Map<String, Master> masters = Maps.newHashMap();
private final Function<MasterSpec, IMachine> mastersLoader; private final Function<MasterSpec, IMachine> masterCreatorAndInstaller;
private final Map<String, YamlImage> imageMapping; private final Map<String, YamlImage> imageMapping;
private final String workingDir; private final String workingDir;
private final String adminDisk; private final String adminDisk;
private final String guestAdditionsIso; private final String guestAdditionsIso;
private final String installationKeySequence; private final String installationKeySequence;
private final String isosDir; private final String isosDir;
private Supplier<VirtualBoxManager> manager;
@Inject @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_INSTALLATION_KEY_SEQUENCE) String installationKeySequence,
@Named(VIRTUALBOX_WORKINGDIR) String workingDir, Function<MasterSpec, IMachine> masterLoader, @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(version, "version");
checkNotNull(installationKeySequence, "installationKeySequence"); checkNotNull(installationKeySequence, "installationKeySequence");
this.mastersLoader = masterLoader; checkNotNull(manager, "vboxmanager");
this.manager = manager;
this.masterCreatorAndInstaller = masterLoader;
this.installationKeySequence = installationKeySequence; this.installationKeySequence = installationKeySequence;
this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR : workingDir; this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR : workingDir;
File wdFile = new File(this.workingDir); File wdFile = new File(this.workingDir);
@ -100,13 +107,12 @@ public class MasterImages extends AbstractLoadingCache<Image, IMachine> {
} }
@Override @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())) { if (masters.containsKey(key.getId())) {
return masters.get(key); return masters.get(key);
} }
checkNotNull(key, "key");
// the yaml image // the yaml image
YamlImage yamlImage = imageMapping.get(key.getId()); 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("") VmSpec vmSpecification = VmSpec.builder().id(yamlImage.id).name(vmName).memoryMB(512).osTypeId("")
.controller(ideController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build(); .controller(ideController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build();
NetworkAdapter networkAdapter = NetworkAdapter.builder() NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
.networkAttachmentType(NetworkAttachmentType.NAT)
.tcpRedirectRule("127.0.0.1", 2222, "", 22).build(); .tcpRedirectRule("127.0.0.1", 2222, "", 22).build();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard
.builder().addNetworkAdapter(networkAdapter).build();
NetworkSpec networkSpec = NetworkSpec.builder() NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
.addNIC(0L, networkInterfaceCard).build(); .build();
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(0L, networkInterfaceCard).build();
MasterSpec masterSpec = MasterSpec MasterSpec masterSpec = MasterSpec
.builder() .builder()
@ -140,12 +145,25 @@ public class MasterImages extends AbstractLoadingCache<Image, IMachine> {
.iso( .iso(
IsoSpec.builder().sourcePath(localIsoUrl) IsoSpec.builder().sourcePath(localIsoUrl)
.installationScript(installationKeySequence.replace("HOSTNAME", vmSpecification.getVmName())).build()) .installationScript(installationKeySequence.replace("HOSTNAME", vmSpecification.getVmName())).build())
.network(networkSpec) .network(networkSpec).build();
.build();
IMachine masterMachine = mastersLoader.apply(masterSpec); IMachine masterMachine;
masters.put(key.getId(), masterMachine);
return 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 { private String getFilePathOrDownload(String httpUrl) throws ExecutionException {
@ -158,7 +176,7 @@ public class MasterImages extends AbstractLoadingCache<Image, IMachine> {
} }
@Override @Override
public IMachine getIfPresent(Image key) { public Master getIfPresent(Image key) {
if (masters.containsKey(key.getId())) { if (masters.containsKey(key.getId())) {
return masters.get(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; package org.jclouds.virtualbox.functions;
import javax.inject.Inject;
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials; 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.IMachine;
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Function; 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 private final Supplier<VirtualBoxManager> manager;
public NodeAndInitialCredentials<IMachine> apply(IMachine input) { private final Function<CloneSpec, IMachine> cloner;
throw new UnsupportedOperationException();
@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

@ -59,166 +59,165 @@ import com.google.inject.Inject;
@Singleton @Singleton
public class MachineUtils { public class MachineUtils {
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private final Supplier<VirtualBoxManager> manager; private final Supplier<VirtualBoxManager> manager;
private final Factory scriptRunner; private final Factory scriptRunner;
private final Supplier<NodeMetadata> host; private final Supplier<NodeMetadata> host;
@Inject @Inject
public MachineUtils(Supplier<VirtualBoxManager> manager, RunScriptOnNode.Factory scriptRunner, Supplier<NodeMetadata> host) { public MachineUtils(Supplier<VirtualBoxManager> manager, RunScriptOnNode.Factory scriptRunner,
super(); Supplier<NodeMetadata> host) {
this.manager = manager; super();
this.scriptRunner = scriptRunner; this.manager = manager;
this.host = host; this.scriptRunner = scriptRunner;
} this.host = host;
}
public ListenableFuture<ExecResponse> runScriptOnNode(NodeMetadata metadata, Statement statement, public ListenableFuture<ExecResponse> runScriptOnNode(NodeMetadata metadata, Statement statement,
RunScriptOptions options) { RunScriptOptions options) {
return scriptRunner.submit(metadata, statement, options); return scriptRunner.submit(metadata, statement, options);
} }
/** /**
* Locks the machine and executes the given function using the machine * Locks the machine and executes the given function using the machine matching the given id. Since the machine is
* matching the given id. Since the machine is locked it is possible to * locked it is possible to perform some modifications to the IMachine.
* perform some modifications to the IMachine. * <p/>
* <p/> * Unlocks the machine before returning.
* Unlocks the machine before returning. *
* * @param machineId
* @param machineId the id of the machine * the id of the machine
* @param function the function to execute * @param function
* @return the result from applying the function to the machine. * 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, public <T> T writeLockMachineAndApply(final String machineId, final Function<IMachine, T> function) {
new Function<ISession, T>() { return lockSessionOnMachineAndApply(machineId, LockType.Write, new Function<ISession, T>() {
@Override @Override
public T apply(ISession session) { public T apply(ISession session) {
return function.apply(session.getMachine()); return function.apply(session.getMachine());
}
@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);
} }
}
private ISession lockSessionOnMachine(LockType type, String machineId) { @Override
return new MutableMachine(manager, type).apply(machineId); 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); IMachine immutableMachine = manager.get().getVBox().findMachine(machineId);
if (immutableMachine.getSessionState().equals(SessionState.Locked)) { return function.apply(immutableMachine);
Statement kill = newStatementList(call("default"),
findPid(immutableMachine.getSessionPid().toString()), kill()); } catch (VBoxException e) {
scriptRunner throw new RuntimeException(String.format("error applying %s to %s: %s", function, machineId, e.getMessage()), e);
.create(host.get(), kill, }
runAsRoot(false).wrapInInitScript(false)).init().call(); }
/**
* 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
* Unlocks the machine and executes the given function using the machine public String toString() {
* matching the given id. Since the machine is unlocked it is possible to return function.toString();
* 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);
} }
} }.apply(immutableMachine);
}
/**
* 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);
}
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 * @author Andrea Turli
*/ */
@Test(groups = "live", singleThreaded = true, testName = "CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest") @Test(groups = "live", singleThreaded = true, testName = "CloneAndRegisterMachineFromIMachineIfNotAlreadyExistsLiveTest")
public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExistsLiveTest extends
BaseVirtualBoxClientLiveTest { BaseVirtualBoxClientLiveTest {
private static final boolean IS_LINKED_CLONE = true; private static final boolean IS_LINKED_CLONE = true;
@ -61,6 +61,10 @@ public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends
private CleanupMode mode = CleanupMode.Full; private CleanupMode mode = CleanupMode.Full;
private VmSpec clonedVmSpec;
private NetworkSpec cloneNetworkSpec;
@Override @Override
@BeforeClass(groups = "live") @BeforeClass(groups = "live")
public void setupClient() { public void setupClient() {
@ -101,19 +105,20 @@ public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends
NetworkAdapter networkAdapter = NetworkAdapter.builder() NetworkAdapter networkAdapter = NetworkAdapter.builder()
.networkAttachmentType(NetworkAttachmentType.Bridged).build(); .networkAttachmentType(NetworkAttachmentType.Bridged).build();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard
.builder().addNetworkAdapter(networkAdapter).build(); .builder().addNetworkAdapter(networkAdapter).build();
NetworkSpec networkSpec = NetworkSpec.builder() this.cloneNetworkSpec = NetworkSpec.builder()
.addNIC(0L, networkInterfaceCard).build(); .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(); .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 { public void testCloneMachineFromAnotherMachine() throws Exception {
try { try {
IMachine source = getSourceNode(); IMachine source = getSourceNode();
CloneSpec cloneSpec = CloneSpec.builder().vm(clonedVmSpec).network(cloneNetworkSpec).master(source)
.linked(IS_LINKED_CLONE)
.build();
if (source.getCurrentSnapshot() != null) { if (source.getCurrentSnapshot() != null) {
ISession session = manager.get().openMachineSession(source); ISession session = manager.get().openMachineSession(source);
session.getConsole().deleteSnapshot( session.getConsole().deleteSnapshot(
@ -130,8 +137,7 @@ public class CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends
} }
IMachine clone = new CloneAndRegisterMachineFromIMachineIfNotAlreadyExists( IMachine clone = new CloneAndRegisterMachineFromIMachineIfNotAlreadyExists(
manager, workingDir, cloneSpec, IS_LINKED_CLONE, manager, workingDir,machineUtils).apply(cloneSpec);
machineUtils).apply(source);
assertEquals(clone.getName(), cloneSpec.getVmSpec().getVmName()); assertEquals(clone.getName(), cloneSpec.getVmSpec().getVmName());
} finally { } finally {
for (VmSpec spec : ImmutableSet.of(cloneSpec.getVmSpec(), for (VmSpec spec : ImmutableSet.of(cloneSpec.getVmSpec(),