From d0b4d81f9ffd299d1e9f8c5de1ec0e3b558937bd Mon Sep 17 00:00:00 2001 From: David Ribeiro Alves Date: Mon, 5 Mar 2012 01:09:13 +0000 Subject: [PATCH] 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 --- .../VirtualBoxComputeServiceAdapter.java | 16 +- ...VirtualBoxComputeServiceContextModule.java | 14 +- .../jclouds/virtualbox/domain/CloneSpec.java | 35 +- .../org/jclouds/virtualbox/domain/Master.java | 67 ++++ .../jclouds/virtualbox/domain/MasterSpec.java | 2 +- .../jclouds/virtualbox/domain/NodeSpec.java | 92 ++++++ ...MachineFromIMachineIfNotAlreadyExists.java | 17 +- .../functions/CreateAndInstallVm.java | 1 - ...isterMachineFromIsoIfNotAlreadyExists.java | 6 +- .../{MasterImages.java => MastersCache.java} | 64 ++-- .../virtualbox/functions/NodeCreator.java | 53 +++- .../jclouds/virtualbox/util/MachineUtils.java | 299 +++++++++--------- ...omIMachineIfNotAlreadyExistsLiveTest.java} | 26 +- 13 files changed, 472 insertions(+), 220 deletions(-) create mode 100644 labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/Master.java create mode 100644 labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/NodeSpec.java rename labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/{MasterImages.java => MastersCache.java} (78%) rename labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/{CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java => CloneAndRegisterMachineFromIMachineIfNotAlreadyExistsLiveTest.java} (89%) diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java index c6f0d0ab81..6b73e05a67 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapter.java @@ -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 manager; private final Map images; - private final LoadingCache mastersLoader; - private final Function> cloneCreator; + private final LoadingCache mastersLoader; + private final Function> cloneCreator; @Inject public VirtualBoxComputeServiceAdapter(Supplier manager, - Supplier> imagesMapper, LoadingCache mastersLoader, - Function> cloneCreator) { + Supplier> imagesMapper, LoadingCache mastersLoader, + Function> cloneCreator) { this.manager = checkNotNull(manager, "manager"); this.images = imagesMapper.get(); this.mastersLoader = mastersLoader; @@ -79,8 +80,9 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter 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); } diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java index 73aea1a23a..de91ee061c 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java @@ -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>() { }).to((Class) YamlImagesFromFileConfig.class); // the master machines cache - bind(new TypeLiteral>() { - }).to((Class) MasterImages.class); + bind(new TypeLiteral>() { + }).to((Class) MastersCache.class); // the master creating function bind(new TypeLiteral>() { }).to((Class) CreateAndInstallVm.class); // the machine cloning function bind(new TypeLiteral>>() { }).to((Class) NodeCreator.class); + bind(new TypeLiteral>() { + }).to((Class) CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.class); // for byon bind(new TypeLiteral>() { diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/CloneSpec.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/CloneSpec.java index 8f30067808..f12c0493f2 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/CloneSpec.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/CloneSpec.java @@ -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) { diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/Master.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/Master.java new file mode 100644 index 0000000000..d440682c90 --- /dev/null +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/Master.java @@ -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; + } + +} diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/MasterSpec.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/MasterSpec.java index 3c0d6256cc..3b618253f4 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/MasterSpec.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/MasterSpec.java @@ -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"); diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/NodeSpec.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/NodeSpec.java new file mode 100644 index 0000000000..0670dd7471 --- /dev/null +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/NodeSpec.java @@ -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; + } + +} diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java index bfec54ba54..54eb49535f 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java @@ -52,7 +52,7 @@ import com.google.inject.Inject; * @author Andrea Turli */ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements - Function { + Function { @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) @@ -60,24 +60,20 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements private final Supplier manager; private final String workingDir; - private final CloneSpec cloneSpec; - private final boolean isLinkedClone; private final MachineUtils machineUtils; @Inject public CloneAndRegisterMachineFromIMachineIfNotAlreadyExists( Supplier 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 diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java index 2bc4718da5..2758df0cbf 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java @@ -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; diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExists.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExists.java index aef24b199b..4f974178fc 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExists.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndRegisterMachineFromIsoIfNotAlreadyExists.java @@ -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); diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MasterImages.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersCache.java similarity index 78% rename from labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MasterImages.java rename to labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersCache.java index 3586e2dd48..9b6c2005f0 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MasterImages.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersCache.java @@ -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 { +public class MastersCache extends AbstractLoadingCache { - private final Map masters = Maps.newHashMap(); - private final Function mastersLoader; + private final Map masters = Maps.newHashMap(); + private final Function masterCreatorAndInstaller; private final Map imageMapping; private final String workingDir; private final String adminDisk; private final String guestAdditionsIso; private final String installationKeySequence; private final String isosDir; + private Supplier 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 masterLoader, - Supplier> yamlMapper) { + Supplier> yamlMapper, Supplier 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 { } @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 { 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 { .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 { } @Override - public IMachine getIfPresent(Image key) { + public Master getIfPresent(Image key) { if (masters.containsKey(key.getId())) { return masters.get(key.getId()); } diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java index c1715dba04..51f7c030c9 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java @@ -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> { +public class NodeCreator implements Function> { - @Override - public NodeAndInitialCredentials apply(IMachine input) { - throw new UnsupportedOperationException(); + private final Supplier manager; + private final Function cloner; + + @Inject + public NodeCreator(Supplier manager, Function cloner) { + this.manager = manager; + this.cloner = cloner; } + @Override + public NodeAndInitialCredentials 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(); + } + + + + } } diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineUtils.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineUtils.java index 12573b72ab..6b17466b96 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineUtils.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineUtils.java @@ -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 manager; - private final Factory scriptRunner; - private final Supplier host; + private final Supplier manager; + private final Factory scriptRunner; + private final Supplier host; - @Inject - public MachineUtils(Supplier manager, RunScriptOnNode.Factory scriptRunner, Supplier host) { - super(); - this.manager = manager; - this.scriptRunner = scriptRunner; - this.host = host; - } - - public ListenableFuture runScriptOnNode(NodeMetadata metadata, Statement statement, - RunScriptOptions options) { - return scriptRunner.submit(metadata, statement, options); - } + @Inject + public MachineUtils(Supplier manager, RunScriptOnNode.Factory scriptRunner, + Supplier 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. - *

- * 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 writeLockMachineAndApply(final String machineId, final Function function) { - return lockSessionOnMachineAndApply(machineId, LockType.Write, - new Function() { + public ListenableFuture 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. + *

+ * 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 writeLockMachineAndApply(final String machineId, final Function function) { + return lockSessionOnMachineAndApply(machineId, LockType.Write, new Function() { - @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. - *

- * 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 lockSessionOnMachineAndApply(String machineId, LockType type, Function 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. + *

+ * 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 lockSessionOnMachineAndApply(String machineId, LockType type, Function 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. + *

+ *

+ *

Note!

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 unlockMachineAndApply(final String machineId, final Function 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. + *

+ * + * @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 unlockMachineAndApplyOrReturnNullIfNotRegistered(String machineId, Function 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 applyForMachine(final String machineId, final Function function) { + final IMachine immutableMachine = manager.get().getVBox().findMachine(machineId); + return new Function() { + @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. - *

- *

- *

Note!

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 unlockMachineAndApply(final String machineId, final Function 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. - *

- * - * @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 unlockMachineAndApplyOrReturnNullIfNotRegistered(String machineId, - Function 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 applyForMachine(final String machineId, final Function function) { - final IMachine immutableMachine = manager.get().getVBox().findMachine(machineId); - return new Function() { - @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 {"); + } } diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExistsLiveTest.java similarity index 89% rename from labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java rename to labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExistsLiveTest.java index 8d3def7ceb..b85d823cd4 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExistsLiveTest.java @@ -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(),