From dc212cf4602fd67c663abf5f814edf5b58750a85 Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Wed, 12 Sep 2012 08:41:18 +0200 Subject: [PATCH] issue 384: added support for ubuntu12.04; prepared for supporting remote host --- labs/virtualbox/README.md | 18 +- labs/virtualbox/pom.xml | 7 +- .../virtualbox/VirtualBoxApiMetadata.java | 14 +- ...rdcodeLocalhostAsNodeMetadataSupplier.java | 11 +- ...VirtualBoxComputeServiceContextModule.java | 5 +- .../config/VirtualBoxConstants.java | 3 + .../jclouds/virtualbox/domain/YamlImage.java | 3 +- ...MachineFromIMachineIfNotAlreadyExists.java | 17 +- .../functions/CreateAndInstallVm.java | 22 +- .../HardcodedHostToHostNodeMetadata.java | 83 ++++ .../functions/IMachineToNodeMetadata.java | 50 +-- .../functions/IMachineToSshClient.java | 12 +- .../functions/IpAddressesLoadingCache.java | 95 +++++ .../functions/MastersLoadingCache.java | 386 +++++++++++------- .../virtualbox/functions/NodeCreator.java | 155 ++++--- .../admin/StartVBoxIfNotAlreadyRunning.java | 70 +++- .../statements/EnableNetworkInterface.java | 3 - .../jclouds/virtualbox/util/MachineUtils.java | 93 ++--- .../src/main/resources/default-images.yaml | 89 +++- .../BaseVirtualBoxClientLiveTest.java | 10 +- .../virtualbox/PreseedCfgServerTest.java | 1 - ...rtualBoxComputeServiceAdapterLiveTest.java | 4 +- .../compute/VirtualBoxExperimentLiveTest.java | 5 +- .../VirtualBoxImageExtensionLiveTest.java | 19 + .../functions/CreateAndInstallVmLiveTest.java | 62 +-- .../StartVBoxIfNotAlreadyRunningLiveTest.java | 20 +- .../GuestAdditionsInstallerLiveTest.java | 24 +- .../util/MachineControllerLiveTest.java | 34 +- .../src/test/resources/default-images.yaml | 90 +++- 29 files changed, 911 insertions(+), 494 deletions(-) create mode 100644 labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/HardcodedHostToHostNodeMetadata.java create mode 100644 labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IpAddressesLoadingCache.java diff --git a/labs/virtualbox/README.md b/labs/virtualbox/README.md index 9b7e26d86a..b618fa9d92 100644 --- a/labs/virtualbox/README.md +++ b/labs/virtualbox/README.md @@ -1,11 +1,19 @@ #Setup -Have virtualbox 4.1.8 installed. +Have virtualbox 4.1.20r80170 installed. Have an ssh daemon with passwordless login to localhost (i.e. "ssh [me]@localhost" must work without password). +To achieve that, be sure you have your ssh public key (at System.getProperty("user.home") + "/.ssh/id_rsa") in your '.ssh/authorized_keys'. +Please look at [this example]http://www.linuxproblem.org/art_9.html for more details. -That's it! +You can have also specify '-Dvirtualbox.identity' and '-Dvirtualbox.credential' if you want to use a username and password of your local machine. + +In order to make available a preseed file, jclouds-vbox will start a PreseedServer at `http://localhost:23232` that will serve a preseed.cfg file. +Make sure your firewall rules are not blocking this port. +If you need to override this default you can use -Djclouds.virtualbox.preconfigurationurl=http://localhost:PORT/preseed.cfg, with a different PORT. + +That's it! -------------- @@ -17,7 +25,7 @@ Enjoy local cloud goodness by running: > (use 'org.jclouds.compute2) > (import 'org.jclouds.scriptbuilder.statements.login.AdminAccess) -> (def compute (compute-service "virtualbox" "admin" "12345" :sshj :slf4j)) +> (def compute (compute-service "virtualbox" "user" "password" :sshj :slf4j)) > (create-nodes compute "local-cluster" 2 (build-template compute { :run-script (AdminAccess/standard) } )) -------------- @@ -39,8 +47,8 @@ It *should* behave as any other provider, if not please report. - jclouds-vbox is still at alpha stage please report any issues you find. - jclouds-vbox has been mostly tested on Mac OSX, it might work on Linux iff vbox is running and correctly set up, but it won't work on windows for the moment. -- cached isos, vm's and most configs are kept at ~/.jclouds-vbox/ by default. -- jclouds-vbox assumes vbox has the default host-only network vboxnet0, that the network is in 192.168.86.0/255.255.255.0 and that the host has address 1 in this network. +- cached isos, vm's and most configs are kept at ~/.jclouds-vbox/ by default, you can override -Dtest.virtualbox.workingDir=/path/to/your/workingDir. +- jclouds-vbox assumes vbox has the default host-only network vboxnet0, that the network is in 192.168.86.0/255.255.255.0 and that the host has address 1 in this network. -------------- diff --git a/labs/virtualbox/pom.xml b/labs/virtualbox/pom.xml index 820018decf..27c6c93b52 100644 --- a/labs/virtualbox/pom.xml +++ b/labs/virtualbox/pom.xml @@ -37,10 +37,10 @@ http://localhost:18083/ 4.1.4 - 4.1.8r75467 + 4.1.20r80170 administrator - 12345 - imageId=test-ubuntu-11.10-i386,loginUser=toor:password,authenticateSudo=true + CHANGE_ME + osFamily=UBUNTU,osVersionMatches=12.04.1,os64Bit=true,osArchMatches=amd64,loginUser=toor:password,authenticateSudo=true org.jclouds.virtualbox*;version="${project.version}" org.jclouds*;version="${project.version}",* @@ -136,6 +136,7 @@ 1 + false ${test.virtualbox.endpoint} ${test.virtualbox.api-version} diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxApiMetadata.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxApiMetadata.java index f7c1b7fef9..6fd60045c8 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxApiMetadata.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxApiMetadata.java @@ -20,6 +20,8 @@ package org.jclouds.virtualbox; import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAULT_DIR; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_CREDENTIAL; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_IDENTITY; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGES_DESCRIPTOR; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_PRECONFIGURATION_URL; @@ -81,7 +83,13 @@ public class VirtualBoxApiMetadata extends BaseApiMetadata { properties.put(VIRTUALBOX_IMAGES_DESCRIPTOR, yamlDescriptor); properties.put(VIRTUALBOX_PRECONFIGURATION_URL, "http://10.0.2.2:23232/preseed.cfg"); - properties.setProperty(TEMPLATE, "osFamily=UBUNTU,osVersionMatches=11.10,os64Bit=true,osArchMatches=x86,loginUser=toor:password,authenticateSudo=true"); + + properties.put(VIRTUALBOX_GUEST_IDENTITY, "toor"); + properties.put(VIRTUALBOX_GUEST_CREDENTIAL, "password"); + properties.setProperty(TEMPLATE, + String.format("osFamily=UBUNTU,osVersionMatches=12.04.1,os64Bit=true,osArchMatches=amd64,loginUser=%s:%s,authenticateSudo=true", + properties.getProperty(VIRTUALBOX_GUEST_IDENTITY), + properties.getProperty(VIRTUALBOX_GUEST_CREDENTIAL))); return properties; } @@ -93,8 +101,8 @@ public class VirtualBoxApiMetadata extends BaseApiMetadata { .identityName("User") .credentialName("Password") .documentation(URI.create("https://www.virtualbox.org/sdkref/index.html")) - .defaultIdentity("administrator") - .defaultCredential("12345") + .defaultIdentity(System.getProperty("user.name")) + .defaultCredential("CHANGE_ME") .defaultEndpoint("http://localhost:18083/") .documentation(URI.create("https://github.com/jclouds/jclouds/tree/master/apis/byon")) // later version not in maven, yet diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/HardcodeLocalhostAsNodeMetadataSupplier.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/HardcodeLocalhostAsNodeMetadataSupplier.java index 814a6c9c1f..ce598d4037 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/HardcodeLocalhostAsNodeMetadataSupplier.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/HardcodeLocalhostAsNodeMetadataSupplier.java @@ -35,6 +35,7 @@ import org.jclouds.domain.LocationScope; import org.jclouds.domain.LoginCredentials; import com.google.common.base.Charsets; +import com.google.common.base.Strings; import com.google.common.base.Supplier; import com.google.common.base.Throwables; import com.google.common.io.Files; @@ -79,7 +80,7 @@ import com.google.inject.Provides; public class HardcodeLocalhostAsNodeMetadataSupplier extends AbstractModule { public static final String HOST_ID = "host"; - public static final String HOSTNAME = System.getenv("HOSTNAME"); + public static final String HOSTNAME = Strings.nullToEmpty(System.getenv("HOSTNAME")); /** * Lazy so that we don't hang up the injector reading a file @@ -91,9 +92,7 @@ public class HardcodeLocalhostAsNodeMetadataSupplier extends AbstractModule { @Override public NodeMetadata get() { - String privateKey = readRsaIdentity(); - return new NodeMetadataBuilder() .id(HOST_ID) .name("host installing virtualbox") @@ -110,9 +109,9 @@ public class HardcodeLocalhostAsNodeMetadataSupplier extends AbstractModule { .description(HOSTNAME) .build()) .credentials(LoginCredentials.builder() - .user(System.getProperty("user.name")) - .privateKey(privateKey) - .build()) + .user(System.getProperty("user.name")) + .privateKey(privateKey) + .build()) .build(); } 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 7fe2b90c26..d65bd8584b 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 @@ -150,7 +150,10 @@ public class VirtualBoxComputeServiceContextModule extends @Override public VirtualBoxManager apply(Supplier nodeSupplier) { - return VirtualBoxManager.createInstance(nodeSupplier.get().getId()); + if(nodeSupplier.get().getId() != null) + return VirtualBoxManager.createInstance(nodeSupplier.get().getId()); + + return VirtualBoxManager.createInstance(""); } @Override diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxConstants.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxConstants.java index 46a6e67ac5..e0c8442435 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxConstants.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxConstants.java @@ -61,5 +61,8 @@ public interface VirtualBoxConstants { + ".jclouds-vbox"; public static final String VIRTUALBOX_PROVIDER = "virtualbox"; + + public static final String VIRTUALBOX_GUEST_IDENTITY = "jclouds.virtualbox.guest.identity"; + public static final String VIRTUALBOX_GUEST_CREDENTIAL = "jclouds.virtualbox.guest.credential"; } diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/YamlImage.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/YamlImage.java index bff48a2632..8a45140ffa 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/YamlImage.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/YamlImage.java @@ -118,6 +118,7 @@ public class YamlImage { public String os_family; public String os_description; public String os_version; + public String iso_md5; public String iso; public String keystroke_sequence; public String preseed_cfg; @@ -154,7 +155,7 @@ public class YamlImage { public String toString() { return "YamlImage [id=" + id + ", name=" + name + ", description=" + description + ", hostname=" + hostname + ", location_id=" + location_id + ", os_arch=" + os_arch + ", os_family=" + os_family - + ", os_description=" + os_description + ", os_version=" + os_version + ", iso=" + iso + + ", os_description=" + os_description + ", os_version=" + os_version + ", iso=" + iso + ", keystroke_sequence=" + keystroke_sequence + ", preseed_cfg=" + preseed_cfg + ", login_port=" + login_port + ", os_64bit=" + os_64bit + ", group=" + group + ", tags=" + tags + ", metadata=" + metadata + ", username=" + username + ", credential=" + credential + ", credential_url=" 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 46521df88a..0985deb519 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 @@ -21,6 +21,7 @@ package org.jclouds.virtualbox.functions; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.locks.ReentrantLock; import javax.annotation.Resource; import javax.inject.Named; @@ -60,6 +61,8 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements Fu private final Supplier manager; private final String workingDir; private final MachineUtils machineUtils; + + private final ReentrantLock lock = new ReentrantLock(); @Inject public CloneAndRegisterMachineFromIMachineIfNotAlreadyExists(Supplier manager, @@ -104,15 +107,13 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements Fu if (isLinkedClone) options.add(CloneOptions.Link); - // TODO snapshot name - ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "snapshotName", "snapshotDesc", logger) - .apply(master); - - // clone - IProgress progress = currentSnapshot.getMachine().cloneTo(clonedMachine, CloneMode.MachineState, options); - + ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, + "snapshotName", "snapshotDesc", logger).apply(master); + IProgress progress = currentSnapshot.getMachine().cloneTo(clonedMachine, + CloneMode.MachineState, options); progress.waitForCompletion(-1); - logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName())); + logger.debug(String.format("Machine %s is cloned correctly", + clonedMachine.getName())); // memory may not be the same as the master vm clonedMachine.setMemorySize(cloneSpec.getVmSpec().getMemory()); 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 b359cd47ff..ff013ede56 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 @@ -42,7 +42,9 @@ import org.jclouds.virtualbox.domain.VmSpec; import org.jclouds.virtualbox.statements.InstallGuestAdditions; import org.jclouds.virtualbox.util.MachineController; import org.jclouds.virtualbox.util.MachineUtils; +import org.virtualbox_4_1.DeviceType; import org.virtualbox_4_1.IMachine; +import org.virtualbox_4_1.IMediumAttachment; import com.google.common.base.Function; import com.google.common.base.Predicate; @@ -88,19 +90,14 @@ public class CreateAndInstallVm implements Function { @Override public IMachine apply(MasterSpec masterSpec) { - VmSpec vmSpec = masterSpec.getVmSpec(); IsoSpec isoSpec = masterSpec.getIsoSpec(); String vmName = vmSpec.getVmName(); - IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists.apply(masterSpec); - // Launch machine and wait for it to come online machineController.ensureMachineIsLaunched(vmName); - String installationKeySequence = isoSpec.getInstallationKeySequence().replace("PRECONFIGURATION_URL", preconfigurationUrl); - configureOsInstallationWithKeyboardSequence(vmName, installationKeySequence); // the OS installation is a long process: let's delay the check for ssh of 30 sec @@ -111,11 +108,8 @@ public class CreateAndInstallVm implements Function { } SshClient client = sshClientForIMachine.apply(vm); - logger.debug(">> awaiting installation to finish node(%s)", vmName); - checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh", vmName); - NodeMetadata nodeMetadata = imachineToNodeMetadata.apply(vm); logger.debug(">> awaiting post-installation actions on vm: %s", vmName); @@ -129,9 +123,17 @@ public class CreateAndInstallVm implements Function { new InstallGuestAdditions(vmSpec, version), RunScriptOptions.NONE); ExecResponse gaInstallationResponse = Futures.getUnchecked(execInstallGA); checkState(gaInstallationResponse.getExitStatus() == 0); - machineController.ensureMachineIsShutdown(vmName); - + Iterable mediumAttachments = Iterables.filter(vm.getMediumAttachmentsOfController("IDE Controller"), + new Predicate() { + public boolean apply(IMediumAttachment in) { + return in.getMedium() != null && in.getMedium().getDeviceType().equals(DeviceType.DVD); + } + }); + for (IMediumAttachment iMediumAttachment : mediumAttachments) { + machineUtils.writeLockMachineAndApply(vm.getName(), new DetachDistroMediumFromMachine( + iMediumAttachment.getController(), iMediumAttachment.getPort(), iMediumAttachment.getDevice())); + } return vm; } diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/HardcodedHostToHostNodeMetadata.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/HardcodedHostToHostNodeMetadata.java new file mode 100644 index 0000000000..8f09c67d22 --- /dev/null +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/HardcodedHostToHostNodeMetadata.java @@ -0,0 +1,83 @@ +/** + * 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 static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; + +import javax.annotation.Resource; +import javax.inject.Named; + +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.NodeMetadataBuilder; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.location.Provider; +import org.jclouds.logging.Logger; +import org.jclouds.rest.annotations.Credential; +import org.jclouds.rest.annotations.Identity; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableList; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +@Singleton +public class HardcodedHostToHostNodeMetadata implements + Function { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final Supplier providerSupplier; + private final String username; + private final String password; + + @Inject + public HardcodedHostToHostNodeMetadata( + @Provider Supplier providerSupplier, + @Nullable @Identity String identity, + @Nullable @Credential String credential) { + this.providerSupplier = checkNotNull(providerSupplier, + "endpoint to virtualbox websrvd is needed"); + this.username = identity; + this.password = credential.equals("CHANGE_ME") ? "" : credential; + } + + @Override + public NodeMetadata apply(NodeMetadata host) { + + LoginCredentials.Builder credentialsBuilder = LoginCredentials.builder( + host.getCredentials()).user(username); + if (!password.isEmpty()) + credentialsBuilder.password(password); + + return NodeMetadataBuilder + .fromNodeMetadata(host) + .credentials(credentialsBuilder.build()) + .publicAddresses(ImmutableList.of(providerSupplier.get().getHost())) + .build(); + } + +} diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java index d985d050cd..499fca7da1 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java @@ -46,7 +46,6 @@ import org.virtualbox_4_1.NetworkAttachmentType; import com.google.common.base.Function; import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -82,7 +81,6 @@ public class IMachineToNodeMetadata implements Function NodeMetadataBuilder nodeMetadataBuilder = new NodeMetadataBuilder(); nodeMetadataBuilder.name(name).ids(vm.getName()).group(group); - // TODO Set up location properly LocationBuilder locationBuilder = new LocationBuilder(); locationBuilder.description(""); @@ -96,41 +94,8 @@ public class IMachineToNodeMetadata implements Function if (nodeState == null) nodeState = Status.UNRECOGNIZED; nodeMetadataBuilder.status(nodeState); - - /* - // nat adapter - INetworkAdapter natAdapter = vm.getNetworkAdapter(0l); - checkNotNull(natAdapter, "slot 0 networkadapter"); - checkState(natAdapter.getAttachmentType() == NetworkAttachmentType.NAT, - "expecting slot 0 to be a NAT attachment type (was: " + natAdapter.getAttachmentType() + ")"); - - int ipTermination = 0; - int inPort = 0; - String hostAddress = ""; - - nodeMetadataBuilder.publicAddresses(ImmutableSet.of(natAdapter.getNatDriver().getHostIP())); - for (String nameProtocolnumberAddressInboudportGuestTargetport : natAdapter.getNatDriver().getRedirects()) { - Iterable stuff = Splitter.on(',').split(nameProtocolnumberAddressInboudportGuestTargetport); - String protocolNumber = Iterables.get(stuff, 1); - hostAddress = Iterables.get(stuff, 2); - String inboundPort = Iterables.get(stuff, 3); - String targetPort = Iterables.get(stuff, 5); - if ("1".equals(protocolNumber) && "22".equals(targetPort)) { - inPort = Integer.parseInt(inboundPort); - ipTermination = inPort % NodeCreator.NODE_PORT_INIT + 2; - } - } - - // only masters use 2222 port - if (inPort == MastersLoadingCache.MASTER_PORT) { - nodeMetadataBuilder.publicAddresses(ImmutableSet.of(hostAddress)).loginPort(inPort); - } else { - nodeMetadataBuilder.privateAddresses(ImmutableSet.of((NodeCreator.VMS_NETWORK + ipTermination) + "")); - nodeMetadataBuilder.publicAddresses(ImmutableSet.of((NodeCreator.VMS_NETWORK + ipTermination) + "")); - } - */ - nodeMetadataBuilder = getIpAddresses(vm, nodeMetadataBuilder); + LoginCredentials loginCredentials = new LoginCredentials("toor", "password", null, true); nodeMetadataBuilder.credentials(loginCredentials); @@ -144,7 +109,9 @@ public class IMachineToNodeMetadata implements Function INetworkAdapter adapter = vm.getNetworkAdapter(slot); if(adapter != null) { if (adapter.getAttachmentType() == NetworkAttachmentType.NAT) { - publicIpAddresses.add(adapter.getNatDriver().getHostIP()); + String hostIP = adapter.getNatDriver().getHostIP(); + if(!hostIP.isEmpty()) + publicIpAddresses.add(hostIP); for (String nameProtocolnumberAddressInboudportGuestTargetport : adapter.getNatDriver().getRedirects()) { Iterable stuff = Splitter.on(',').split(nameProtocolnumberAddressInboudportGuestTargetport); String protocolNumber = Iterables.get(stuff, 1); @@ -153,26 +120,25 @@ public class IMachineToNodeMetadata implements Function String targetPort = Iterables.get(stuff, 5); if ("1".equals(protocolNumber) && "22".equals(targetPort)) { int inPort = Integer.parseInt(inboundPort); - nodeMetadataBuilder.publicAddresses(ImmutableSet.of(hostAddress)).loginPort(inPort); + publicIpAddresses.add(hostAddress); + nodeMetadataBuilder.loginPort(inPort); } //privateIpAddresses.add((NodeCreator.VMS_NETWORK + ipTermination) + ""); } // TODO this could be a public and private address } else if (adapter.getAttachmentType() == NetworkAttachmentType.Bridged) { - String clientIpAddress = machineUtils.getIpAddressFromBridgedNIC(vm.getName()); + String clientIpAddress = machineUtils.getIpAddressFromFirstNIC(vm.getName()); //privateIpAddresses.add(clientIpAddress); publicIpAddresses.add(clientIpAddress); } else if (adapter.getAttachmentType() == NetworkAttachmentType.HostOnly) { - String clientIpAddress = machineUtils.getIpAddressFromHostOnlyNIC(vm.getName()); + String clientIpAddress = machineUtils.getIpAddressFromFirstNIC(vm.getName()); publicIpAddresses.add(clientIpAddress); - } } } nodeMetadataBuilder.publicAddresses(publicIpAddresses); nodeMetadataBuilder.privateAddresses(publicIpAddresses); - return nodeMetadataBuilder; } diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToSshClient.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToSshClient.java index 3c684152b6..adb15aa207 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToSshClient.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToSshClient.java @@ -20,6 +20,8 @@ package org.jclouds.virtualbox.functions; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_CREDENTIAL; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_IDENTITY; import java.util.List; @@ -35,6 +37,7 @@ import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.domain.LoginCredentials; import org.jclouds.logging.Logger; import org.jclouds.ssh.SshClient; +import org.jclouds.virtualbox.VirtualBoxApiMetadata; import org.jclouds.virtualbox.domain.BridgedIf; import org.jclouds.virtualbox.statements.GetIPAddressFromMAC; import org.jclouds.virtualbox.statements.ScanNetworkWithPing; @@ -82,10 +85,11 @@ public class IMachineToSshClient implements Function { String clientIpAddress = null; String sshPort = "22"; - // TODO: we need a way to align the default login credentials - // from the iso with the vmspec -> IMachineToNodeMetadata using YamlImage ? + String guestIdentity = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_IDENTITY); + String guestCredential = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_CREDENTIAL); LoginCredentials loginCredentials = LoginCredentials.builder() - .user("toor").password("password").authenticateSudo(true) + .user(guestIdentity) + .password(guestCredential).authenticateSudo(true) .build(); if (networkAdapter.getAttachmentType() @@ -109,7 +113,7 @@ public class IMachineToSshClient implements Function { clientIpAddress = getIpAddressFromBridgedNIC(networkAdapter, network); } else if (networkAdapter.getAttachmentType().equals( NetworkAttachmentType.HostOnly)) { - clientIpAddress = machineUtils.getIpAddressFromHostOnlyNIC(vm.getName()); + clientIpAddress = machineUtils.getIpAddressFromFirstNIC(vm.getName()); } checkNotNull(clientIpAddress, "clientIpAddress"); diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IpAddressesLoadingCache.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IpAddressesLoadingCache.java new file mode 100644 index 0000000000..c45112a6b7 --- /dev/null +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IpAddressesLoadingCache.java @@ -0,0 +1,95 @@ +/** + * 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 static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; +import org.jclouds.virtualbox.util.MachineUtils; +import org.virtualbox_4_1.VirtualBoxManager; + +import com.google.common.base.Supplier; +import com.google.common.cache.AbstractLoadingCache; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.Maps; + +/** + * A {@link LoadingCache} for ip addresses. If the requested ip address has been + * previously extracted this returns it, if not it calls vbox api. + * + * @author andrea turli + * + */ +@Singleton +public class IpAddressesLoadingCache extends + AbstractLoadingCache { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final Map masters = Maps.newHashMap(); + private final Supplier manager; + + @Inject + public IpAddressesLoadingCache(Supplier manager) { + this.manager = checkNotNull(manager, "vboxmanager"); + } + + @Override + public synchronized String get(String idOrName) throws ExecutionException { + if (masters.containsKey(idOrName)) { + return masters.get(idOrName); + } + + String currentIp = "", previousIp = ""; + int count = 0; + while (count < 3) { + currentIp = ""; + while (!MachineUtils.isIpv4(currentIp)) { + currentIp = manager.get().getVBox().findMachine(idOrName) + .getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP"); + } + + if (previousIp.equals(currentIp)) { + count++; + } + previousIp = currentIp; + } + + masters.put(idOrName, currentIp); + return currentIp; + } + + @Override + public String getIfPresent(Object key) { + return masters.get((String) key); + } + +} diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java index 42f95069d0..04f6f4d702 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java @@ -22,6 +22,7 @@ package org.jclouds.virtualbox.functions; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAULT_DIR; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE; @@ -32,6 +33,8 @@ import static org.jclouds.virtualbox.util.MachineUtils.machineNotFoundException; import java.io.File; import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ExecutionException; @@ -42,10 +45,17 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; +import org.jclouds.compute.callables.RunScriptOnNode.Factory; +import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.location.Provider; import org.jclouds.logging.Logger; import org.jclouds.rest.annotations.BuildVersion; +import org.jclouds.scriptbuilder.domain.Statement; +import org.jclouds.scriptbuilder.domain.StatementList; +import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.virtualbox.domain.HardDisk; import org.jclouds.virtualbox.domain.IsoSpec; import org.jclouds.virtualbox.domain.Master; @@ -57,6 +67,8 @@ import org.jclouds.virtualbox.domain.StorageController; import org.jclouds.virtualbox.domain.VmSpec; import org.jclouds.virtualbox.domain.YamlImage; import org.jclouds.virtualbox.functions.admin.PreseedCfgServer; +import org.jclouds.virtualbox.predicates.RetryIfSocketNotYetOpen; +import org.testng.collections.Lists; import org.virtualbox_4_1.CleanupMode; import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.NetworkAttachmentType; @@ -71,178 +83,236 @@ import com.google.common.cache.AbstractLoadingCache; import com.google.common.cache.LoadingCache; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; +import com.google.common.net.HostAndPort; /** - * A {@link LoadingCache} for masters. If the requested master has been previously created this - * returns it, if not it coordinates its creation including downloading isos and creating - * cache/config directories. This also implements {@link Supplier} in order to provide jetty with - * the current image (only one master can be created at a time). + * A {@link LoadingCache} for masters. If the requested master has been + * previously created this returns it, if not it coordinates its creation + * including downloading isos and creating cache/config directories. This also + * implements {@link Supplier} in order to provide jetty with the current image + * (only one master can be created at a time). * - * @author dralves + * @author dralves, andrea turli * */ @Singleton public class MastersLoadingCache extends AbstractLoadingCache { - // TODO parameterize - public static final int MASTER_PORT = 2222; - public static final String HOST_ONLY_IFACE_NAME = "vboxnet0"; + // TODO parameterize + public static final int MASTER_PORT = 2222; - @Resource - @Named(ComputeServiceConstants.COMPUTE_LOGGER) - protected Logger logger = Logger.NULL; + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; - private final Map masters = Maps.newHashMap(); - private final Function masterCreatorAndInstaller; - private final Map imageMapping; - private final String workingDir; - private final String installationKeySequence; - private final String isosDir; - private final Supplier manager; - private final Function isoDownloader; - private final String version; - private final String preconfigurationUrl; + private final Map masters = Maps.newHashMap(); + private final Function masterCreatorAndInstaller; + private final Map imageMapping; + private final String workingDir; + private final String installationKeySequence; + private final String isosDir; + private final Supplier manager; + private final String version; + private final String preconfigurationUrl; - @Inject - public MastersLoadingCache(@BuildVersion String version, - @Named(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE) String installationKeySequence, - @Named(VIRTUALBOX_PRECONFIGURATION_URL) String preconfigurationUrl, - @Named(VIRTUALBOX_WORKINGDIR) String workingDir, Function masterLoader, - Supplier> yamlMapper, Supplier manager, - Function isoDownloader) { - checkNotNull(version, "version"); - checkNotNull(installationKeySequence, "installationKeySequence"); - checkNotNull(manager, "vboxmanager"); - this.manager = manager; - this.masterCreatorAndInstaller = masterLoader; - this.installationKeySequence = installationKeySequence; - this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR : workingDir; - this.isosDir = workingDir + File.separator + "isos"; - this.imageMapping = Maps.newLinkedHashMap(); - for (Entry entry : yamlMapper.get().entrySet()) { - this.imageMapping.put(entry.getKey().getId(), entry.getValue()); + private final Factory runScriptOnNodeFactory; + private final RetryIfSocketNotYetOpen socketTester; + private final Supplier host; + private final Supplier providerSupplier; + private final HardcodedHostToHostNodeMetadata hardcodedHostToHostNodeMetadata; + + @Inject + public MastersLoadingCache( + @BuildVersion String version, + @Named(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE) String installationKeySequence, + @Named(VIRTUALBOX_PRECONFIGURATION_URL) String preconfigurationUrl, + @Named(VIRTUALBOX_WORKINGDIR) String workingDir, + Function masterLoader, + Supplier> yamlMapper, + Supplier manager, + Factory runScriptOnNodeFactory, + RetryIfSocketNotYetOpen socketTester, Supplier host, + @Provider Supplier providerSupplier, + HardcodedHostToHostNodeMetadata hardcodedHostToHostNodeMetadata) { + checkNotNull(version, "version"); + checkNotNull(installationKeySequence, "installationKeySequence"); + checkNotNull(manager, "vboxmanager"); + this.manager = manager; + this.masterCreatorAndInstaller = masterLoader; + this.installationKeySequence = installationKeySequence; + this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR + : workingDir; + this.isosDir = workingDir + File.separator + "isos"; + this.imageMapping = Maps.newLinkedHashMap(); + for (Entry entry : yamlMapper.get().entrySet()) { + this.imageMapping.put(entry.getKey().getId(), entry.getValue()); + } + this.version = Iterables.get(Splitter.on('r').split(version), 0); + this.preconfigurationUrl = preconfigurationUrl; + + this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, + "runScriptOnNodeFactory"); + this.socketTester = checkNotNull(socketTester, "socketTester"); + this.socketTester.seconds(3L); + this.host = checkNotNull(host, "host"); + this.providerSupplier = checkNotNull(providerSupplier, + "endpoint to virtualbox websrvd is needed"); + this.hardcodedHostToHostNodeMetadata = hardcodedHostToHostNodeMetadata; + } + + @PostConstruct + public void createCacheDirStructure() { + if (!new File(workingDir).exists()) { + new File(workingDir, "isos").mkdirs(); + } + } + + @Override + public synchronized Master get(Image key) throws ExecutionException { + // check if we have loaded this machine before + if (masters.containsKey(key.getId())) { + return masters.get(key.getId()); + } + checkState(!key.getId().contains(VIRTUALBOX_NODE_NAME_SEPARATOR), + "master image names cannot contain \"" + + VIRTUALBOX_NODE_NAME_SEPARATOR + "\""); + String vmName = VIRTUALBOX_IMAGE_PREFIX + key.getId(); + IMachine masterMachine; + Master master; + // ready the preseed file server + PreseedCfgServer server = new PreseedCfgServer(); + try { + // try and find a master machine in vbox + masterMachine = manager.get().getVBox().findMachine(vmName); + master = Master.builder().machine(masterMachine).build(); + } catch (VBoxException e) { + if (machineNotFoundException(e)) { + // machine was not found try to build one from a yaml file + YamlImage currentImage = checkNotNull(imageMapping.get(key.getId()), "currentImage"); + URI preseedServer; + try { + preseedServer = new URI(preconfigurationUrl); + if (!socketTester.apply(HostAndPort.fromParts(preseedServer.getHost(), + preseedServer.getPort()))) { + server.start(preconfigurationUrl, currentImage.preseed_cfg); + } + } catch (URISyntaxException e1) { + throw e; + } + + MasterSpec masterSpec = buildMasterSpecFromYaml(currentImage, + vmName); + + // create the master machine if it can't be found + masterMachine = masterCreatorAndInstaller.apply(masterSpec); + // build the master + master = Master.builder().machine(masterMachine) + .spec(masterSpec).build(); + } else { + throw e; + } + } finally { + server.stop(); + } + + masters.put(key.getId(), master); + return master; + } + + private MasterSpec buildMasterSpecFromYaml(YamlImage currentImage, + String vmName) throws ExecutionException { + String guestAdditionsFileName = String.format( + "VBoxGuestAdditions_%s.iso", version); + String guestAdditionsIso = String.format("%s/%s", isosDir, + guestAdditionsFileName); + String guestAdditionsUri = "http://download.virtualbox.org/virtualbox/" + + version + "/" + guestAdditionsFileName; + if (!new File(guestAdditionsIso).exists()) { + getFilePathOrDownload(guestAdditionsUri, null); + } + // check if the iso is here, download if not + String localIsoUrl = checkNotNull(getFilePathOrDownload(currentImage.iso, currentImage.iso_md5), "distro iso"); + String adminDisk = workingDir + File.separator + vmName + ".vdi"; + HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk) + .autoDelete(true).controllerPort(0).deviceSlot(1).build(); + + StorageController ideController = StorageController.builder() + .name("IDE Controller").bus(StorageBus.IDE) + .attachISO(0, 0, localIsoUrl).attachHardDisk(hardDisk) + .attachISO(1, 0, guestAdditionsIso).build(); + + VmSpec vmSpecification = VmSpec.builder().id(currentImage.id) + .name(vmName).memoryMB(512).osTypeId("") + .controller(ideController).forceOverwrite(true) + .cleanUpMode(CleanupMode.Full).build(); + + NetworkAdapter networkAdapter = NetworkAdapter + .builder() + .networkAttachmentType(NetworkAttachmentType.NAT) + .tcpRedirectRule(providerSupplier.get().getHost(), MASTER_PORT, + "", 22).build(); + + NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard + .builder().addNetworkAdapter(networkAdapter).slot(0L).build(); + + NetworkSpec networkSpec = NetworkSpec.builder() + .addNIC(networkInterfaceCard).build(); + + return MasterSpec + .builder() + .vm(vmSpecification) + .iso(IsoSpec + .builder() + .sourcePath(localIsoUrl) + .installationScript( + installationKeySequence.replace("HOSTNAME", + vmSpecification.getVmName())).build()) + .network(networkSpec).build(); + } + + @Override + public synchronized Master getIfPresent(Object key) { + checkArgument(key instanceof Image, + "this cache is for entries who's keys are Images"); + Image image = Image.class.cast(key); + if (masters.containsKey(image.getId())) { + return masters.get(image.getId()); + } + return null; + } + + private String getFilePathOrDownload(String httpUrl, String md5) + throws ExecutionException { + String fileName = httpUrl.substring(httpUrl.lastIndexOf('/') + 1, + httpUrl.length()); + URI provider = providerSupplier.get(); + if (!socketTester.apply(HostAndPort.fromParts(provider.getHost(), + provider.getPort()))) { + throw new RuntimeException("could not connect to virtualbox"); } - this.version = Iterables.get(Splitter.on('r').split(version), 0); - this.isoDownloader = isoDownloader; - this.preconfigurationUrl = preconfigurationUrl; - } + File file = new File(isosDir, fileName); + List statements = Lists.newArrayList(); + statements.add(Statements.saveHttpResponseTo(URI.create(httpUrl), + isosDir, fileName)); + StatementList statementList = new StatementList(statements); + NodeMetadata hostNodeMetadata = hardcodedHostToHostNodeMetadata + .apply(host.get()); + runScriptOnNodeFactory + .create(hostNodeMetadata, statementList, runAsRoot(false)).init() + .call(); - @PostConstruct - public void createCacheDirStructure() { - if (!new File(workingDir).exists()) { - new File(workingDir, "isos").mkdirs(); + ExecResponse response = runScriptOnNodeFactory + .create( + hostNodeMetadata, + Statements.exec("md5 " + isosDir + File.separator + fileName), + runAsRoot(false)).init().call(); + if (md5 != null) { + if (!Iterables.get( + Splitter.on("=").trimResults().split(response.getOutput()), 1) + .equals(md5)) + return null; } - } - - @Override - public synchronized Master get(Image key) throws ExecutionException { - // check if we have loaded this machine before - if (masters.containsKey(key.getId())) { - return masters.get(key.getId()); - } - - checkState(!key.getId().contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "master image names cannot contain \"" - + VIRTUALBOX_NODE_NAME_SEPARATOR + "\""); - - String vmName = VIRTUALBOX_IMAGE_PREFIX + key.getId(); - - IMachine masterMachine; - - Master master; - - // ready the preseed file server - PreseedCfgServer server = new PreseedCfgServer(); - try { - // try and find a master machine in vbox - masterMachine = manager.get().getVBox().findMachine(vmName); - master = Master.builder().machine(masterMachine).build(); - - } catch (VBoxException e) { - if (machineNotFoundException(e)) { - // machine was not found try to build one from a yaml file - YamlImage currentImage = imageMapping.get(key.getId()); - - checkNotNull(currentImage); - - server.start(preconfigurationUrl, currentImage.preseed_cfg); - - MasterSpec masterSpec = buildMasterSpecFromYaml(currentImage, vmName); - - // create the master machine if it can't be found - masterMachine = masterCreatorAndInstaller.apply(masterSpec); - - // build the master - master = Master.builder().machine(masterMachine).spec(masterSpec).build(); - } else { - throw e; - } - } finally { - server.stop(); - } - - masters.put(key.getId(), master); - return master; - } - - private MasterSpec buildMasterSpecFromYaml(YamlImage currentImage, String vmName) throws ExecutionException { - - String guestAdditionsFileName = String.format("VBoxGuestAdditions_%s.iso", version); - String guestAdditionsIso = String.format("%s/%s", isosDir, guestAdditionsFileName); - String guestAdditionsUri = "http://download.virtualbox.org/virtualbox/" + version + "/" + guestAdditionsFileName; - if (!new File(guestAdditionsIso).exists()) { - getFilePathOrDownload(guestAdditionsUri); - } - checkState(new File(guestAdditionsIso).exists(), "guest additions iso does not exist at: " + guestAdditionsIso); - - // check if the iso is here, download if not - String localIsoUrl = getFilePathOrDownload(currentImage.iso); - - String adminDisk = workingDir + File.separator + vmName + ".vdi"; - - HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk).autoDelete(true).controllerPort(0).deviceSlot(1) - .build(); - - StorageController ideController = StorageController.builder().name("IDE Controller").bus(StorageBus.IDE) - .attachISO(0, 0, localIsoUrl).attachHardDisk(hardDisk).attachISO(1, 0, guestAdditionsIso).build(); - - VmSpec vmSpecification = VmSpec.builder().id(currentImage.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", MASTER_PORT, "", 22).build(); - - NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter) - .slot(0L).build(); - - NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build(); - - return MasterSpec - .builder() - .vm(vmSpecification) - .iso(IsoSpec.builder().sourcePath(localIsoUrl) - .installationScript(installationKeySequence.replace("HOSTNAME", vmSpecification.getVmName())) - .build()).network(networkSpec).build(); - } - - @Override - public synchronized Master getIfPresent(Object key) { - checkArgument(key instanceof Image, "this cache is for entries who's keys are Images"); - Image image = Image.class.cast(key); - if (masters.containsKey(image.getId())) { - return masters.get(image.getId()); - } - return null; - } - - private String getFilePathOrDownload(String httpUrl) throws ExecutionException { - String fileName = httpUrl.substring(httpUrl.lastIndexOf('/') + 1, httpUrl.length()); - File localFile = new File(isosDir, fileName); - if (!localFile.exists()) { - logger.debug("iso not found in cache, downloading: %s", httpUrl); - localFile = isoDownloader.apply(URI.create(httpUrl)); - } - checkState(localFile.exists(), "iso file has not been downloaded: " + fileName); - return localFile.getAbsolutePath(); + return file.getAbsolutePath(); } } 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 d417afbfee..e9f6f289a9 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 @@ -22,10 +22,13 @@ package org.jclouds.virtualbox.functions; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_CREDENTIAL; +import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_IDENTITY; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_NAME_SEPARATOR; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX; +import java.net.URI; import java.util.List; import javax.inject.Inject; @@ -39,7 +42,12 @@ import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadataBuilder; import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.domain.LoginCredentials; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.location.Provider; +import org.jclouds.rest.annotations.Credential; +import org.jclouds.rest.annotations.Identity; import org.jclouds.scriptbuilder.domain.Statements; +import org.jclouds.virtualbox.VirtualBoxApiMetadata; import org.jclouds.virtualbox.config.VirtualBoxComputeServiceContextModule; import org.jclouds.virtualbox.domain.CloneSpec; import org.jclouds.virtualbox.domain.Master; @@ -63,8 +71,10 @@ import org.virtualbox_4_1.NetworkAttachmentType; import org.virtualbox_4_1.VirtualBoxManager; import com.google.common.base.Function; +import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; @@ -84,29 +94,36 @@ public class NodeCreator implements Function host; - - + private final Supplier providerSupplier; + private final String username; + private final String password; + private int ram = 512; + private final String guestIdentity = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_IDENTITY); + private final String guestCredential = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_CREDENTIAL); + @Inject public NodeCreator(Supplier manager, Function cloner, Factory runScriptOnNodeFactory, + MachineUtils machineUtils, RunScriptOnNode.Factory scriptRunnerFactory, MachineController machineController, Supplier host, - MachineUtils machineUtils, RunScriptOnNode.Factory scriptRunnerFactory, MachineController machineController) { + @Provider Supplier providerSupplier, + @Nullable @Identity String identity, + @Nullable @Credential String credential) { this.manager = manager; this.cloner = cloner; this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory"); - this.host = checkNotNull(host, "host"); - this.machineUtils = machineUtils; this.machineController = machineController; + this.host = checkNotNull(host, "host"); + this.providerSupplier = checkNotNull(providerSupplier, + "endpoint to virtualbox websrvd is needed"); + this.username = identity; + this.password = credential; } @Override public synchronized NodeAndInitialCredentials apply(NodeSpec nodeSpec) { - checkNotNull(nodeSpec, "NodeSpec"); - - Master master = nodeSpec.getMaster(); - checkNotNull(master, "Master"); - + Master master = checkNotNull(nodeSpec.getMaster(), "Master"); if (master.getMachine().getCurrentSnapshot() != null) { ISession session; try { @@ -119,40 +136,32 @@ public class NodeCreator implements Function 0) { ram = nodeSpec.getTemplate().getHardware().getRam(); } - - VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(ram).cleanUpMode(CleanupMode.Full) + VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(ram) + .cleanUpMode(CleanupMode.Full) .forceOverwrite(true).build(); - // CASE NAT + HOST-ONLY - NetworkAdapter natAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT) - .build(); - NetworkInterfaceCard natIfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(natAdapter).slot(1L).build(); - - NetworkAdapter hostOnlyAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.HostOnly) - .build(); - - // create new hostOnly interface if needed, otherwise use the one already there with dhcp enabled ... - String hostOnlyIfName = getHostOnlyIfOrCreate(); - - NetworkInterfaceCard hostOnlyIfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(hostOnlyAdapter) - .addHostInterfaceName(hostOnlyIfName).slot(0L).build(); - - NetworkSpec networkSpec = createNetworkSpecForHostOnlyNATNICs(natIfaceCard, hostOnlyIfaceCard); + // case 'vbox host is localhost': NAT + HOST-ONLY + NetworkSpec networkSpec = createNetworkSpecWhenVboxIsLocalhost(); + Optional optionalNatIfaceCard = Iterables.tryFind( + networkSpec.getNetworkInterfaceCards(), + new Predicate() { + @Override + public boolean apply(NetworkInterfaceCard nic) { + return nic.getNetworkAdapter().getNetworkAttachmentType() + .equals(NetworkAttachmentType.NAT); + } + }); CloneSpec cloneSpec = CloneSpec.builder().linked(true).master(master.getMachine()).network(networkSpec) .vm(cloneVmSpec).build(); IMachine cloned = cloner.apply(cloneSpec); - machineController.ensureMachineIsLaunched(cloneVmSpec.getVmName()); // IMachineToNodeMetadata produces the final ip's but these need to be set before so we build a @@ -160,42 +169,55 @@ public class NodeCreator implements Function nodeAndInitialCredentials = new NodeAndInitialCredentials(cloned, - cloneName, LoginCredentials.builder().user("toor").password("password").authenticateSudo(true).build()); - - return nodeAndInitialCredentials; + return new NodeAndInitialCredentials(cloned, + cloneName, LoginCredentials.builder() + .user(guestIdentity) + .password(guestCredential) + .authenticateSudo(true) + .build()); } - + private NodeMetadata buildPartialNodeMetadata(IMachine clone) { NodeMetadataBuilder nodeMetadataBuilder = new NodeMetadataBuilder(); nodeMetadataBuilder.id(clone.getName()); nodeMetadataBuilder.status(VirtualBoxComputeServiceContextModule.toPortableNodeStatus.get(clone.getState())); - nodeMetadataBuilder.publicAddresses(ImmutableSet.of(machineUtils.getIpAddressFromHostOnlyNIC(clone.getName()))); - - LoginCredentials loginCredentials = new LoginCredentials("toor", "password", null, true); - nodeMetadataBuilder.credentials(loginCredentials); - + nodeMetadataBuilder.publicAddresses(ImmutableSet.of(machineUtils.getIpAddressFromFirstNIC(clone.getName()))); + LoginCredentials loginCredentials = new LoginCredentials(guestIdentity, guestCredential, null, true); + nodeMetadataBuilder.credentials(loginCredentials); return nodeMetadataBuilder.build(); } - private NetworkSpec createNetworkSpecForHostOnlyNATNICs(NetworkInterfaceCard natIfaceCard, - NetworkInterfaceCard hostOnlyIfaceCard) { - return NetworkSpec.builder().addNIC(natIfaceCard).addNIC(hostOnlyIfaceCard).build(); + private NetworkSpec createNetworkSpecWhenVboxIsLocalhost() { + NetworkAdapter natAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT) + .build(); + NetworkInterfaceCard natIfaceCard = NetworkInterfaceCard.builder() + .addNetworkAdapter(natAdapter) + .slot(1L) + .build(); + NetworkAdapter hostOnlyAdapter = NetworkAdapter.builder() + .networkAttachmentType(NetworkAttachmentType.HostOnly) + .build(); + // create new hostOnly interface if needed, otherwise use the one already there with dhcp enabled ... + String hostOnlyIfName = getHostOnlyIfOrCreate(); + NetworkInterfaceCard hostOnlyIfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(hostOnlyAdapter) + .addHostInterfaceName(hostOnlyIfName).slot(0L).build(); + return createNetworkSpecForHostOnlyNATNICs(natIfaceCard, hostOnlyIfaceCard); } - /** - * @return - */ + private NetworkSpec createNetworkSpecForHostOnlyNATNICs(NetworkInterfaceCard natIfaceCard, + NetworkInterfaceCard hostOnlyIfaceCard) { + return NetworkSpec.builder() + .addNIC(natIfaceCard) + .addNIC(hostOnlyIfaceCard) + .build(); + } + private String getHostOnlyIfOrCreate() { - IHostNetworkInterface availableHostInterfaceIf = returnExistingHostNetworkInterfaceWithDHCPenabledOrNull(manager .get().getVBox().getHost().getNetworkInterfaces()); if (availableHostInterfaceIf==null) { @@ -205,7 +227,6 @@ public class NodeCreator implements Function availableNetworkInterfaces) { checkNotNull(availableNetworkInterfaces); return Iterables.getFirst(filterAvailableNetworkInterfaceByHostOnlyAndDHCPenabled(availableNetworkInterfaces), null); diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java index 4b5eeba584..b9d21b7fc2 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java @@ -24,22 +24,29 @@ import static com.google.common.base.Preconditions.checkState; import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot; import java.net.URI; +import java.util.List; +import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.compute.callables.RunScriptOnNode.Factory; +import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.location.Provider; import org.jclouds.logging.Logger; +import org.jclouds.scriptbuilder.domain.Statement; +import org.jclouds.scriptbuilder.domain.StatementList; import org.jclouds.scriptbuilder.domain.Statements; +import org.jclouds.virtualbox.functions.HardcodedHostToHostNodeMetadata; import org.jclouds.virtualbox.predicates.RetryIfSocketNotYetOpen; import org.virtualbox_4_1.SessionState; import org.virtualbox_4_1.VirtualBoxManager; +import com.beust.jcommander.internal.Lists; import com.google.common.base.Function; import com.google.common.base.Supplier; import com.google.common.net.HostAndPort; @@ -57,43 +64,74 @@ public class StartVBoxIfNotAlreadyRunning implements Supplier private final Supplier providerSupplier; private final Function, VirtualBoxManager> managerForNode; private transient VirtualBoxManager manager; + private final HardcodedHostToHostNodeMetadata hardcodedHostToHostNodeMetadata; // the functions and suppliers here are to ensure we don't do heavy i/o in injection @Inject public StartVBoxIfNotAlreadyRunning(Function, VirtualBoxManager> managerForNode, Factory runScriptOnNodeFactory, RetryIfSocketNotYetOpen socketTester, Supplier host, - @Provider Supplier providerSupplier) { + @Provider Supplier providerSupplier, + HardcodedHostToHostNodeMetadata hardcodedHostToHostNodeMetadata) { this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory"); this.socketTester = checkNotNull(socketTester, "socketTester"); this.socketTester.seconds(3L); this.host = checkNotNull(host, "host"); this.providerSupplier = checkNotNull(providerSupplier, "endpoint to virtualbox websrvd is needed"); this.managerForNode = checkNotNull(managerForNode, "managerForNode"); - start(); + this.hardcodedHostToHostNodeMetadata = hardcodedHostToHostNodeMetadata; } + @PostConstruct public synchronized void start() { URI provider = providerSupplier.get(); - if (!socketTester.apply(HostAndPort.fromParts(provider.getHost(), provider.getPort()))) { - logger.debug("disabling password access"); - runScriptOnNodeFactory.create(host.get(), Statements.exec("VBoxManage setproperty websrvauthlibrary null"), - runAsRoot(false).wrapInInitScript(false)).init().call(); - logger.debug(">> starting vboxwebsrv"); - String vboxwebsrv = "vboxwebsrv -t 10000 -v -b"; - runScriptOnNodeFactory.create(host.get(), Statements.exec(vboxwebsrv), - runAsRoot(false).wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv")).init().call(); - - if (!socketTester.apply(HostAndPort.fromParts(provider.getHost(), provider.getPort()))){ - throw new RuntimeException("could not connect to virtualbox"); - } + NodeMetadata hostNodeMetadata = hardcodedHostToHostNodeMetadata.apply(host.get()); + // kill previously started vboxwebsrv (possibly dirty session) + List statements = Lists.newArrayList(); + statements.add(Statements.findPid("vboxwebsrv")); + statements.add(Statements.kill()); + StatementList statementList = new StatementList(statements); + + if (socketTester.apply(HostAndPort.fromParts(provider.getHost(), + provider.getPort()))) { + logger.debug(String.format("shutting down previously started vboxwewbsrv at %s", provider)); + ExecResponse execResponse = runScriptOnNodeFactory + .create(hostNodeMetadata, statementList, runAsRoot(false)) + .init().call(); + if(execResponse.getExitStatus()!=0) + throw new RuntimeException("Cannot execute jclouds"); } + + logger.debug("disabling password access"); + runScriptOnNodeFactory + .create( + hostNodeMetadata, + Statements + .exec("VBoxManage setproperty websrvauthlibrary null"), + runAsRoot(false).wrapInInitScript(false)).init().call(); + logger.debug(">> starting vboxwebsrv"); + String vboxwebsrv = "vboxwebsrv -t0 -v -b -H " + + providerSupplier.get().getHost(); + runScriptOnNodeFactory + .create( + hostNodeMetadata, + Statements.exec(vboxwebsrv), + runAsRoot(false).wrapInInitScript(false) + .blockOnComplete(false).nameTask("vboxwebsrv")).init() + .call(); + + if (!socketTester.apply(HostAndPort.fromParts(provider.getHost(), + provider.getPort()))) { + throw new RuntimeException("could not connect to virtualbox"); + } + manager = managerForNode.apply(host); manager.connect(provider.toASCIIString(), "", ""); if (logger.isDebugEnabled()) if (manager.getSessionObject().getState() != SessionState.Unlocked) - logger.warn("manager is not in unlocked state " + manager.getSessionObject().getState()); + logger.warn("manager is not in unlocked state " + + manager.getSessionObject().getState()); } - + @Override public VirtualBoxManager get() { checkState(manager != null, "start not called"); diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/EnableNetworkInterface.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/EnableNetworkInterface.java index 224fd2f7f8..59be70df96 100644 --- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/EnableNetworkInterface.java +++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/EnableNetworkInterface.java @@ -63,9 +63,6 @@ public class EnableNetworkInterface implements Statement { } private List getStatements(String iface) { - /* - * auto eth0 - */ List statements = Lists.newArrayList(); statements.add(exec(String.format("echo auto %s >> /etc/network/interfaces", iface))); // statements.add(exec(String.format("echo iface %s inet dhcp >> /etc/network/interfaces", iface))); // 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 11e627949b..c0d23708c7 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 @@ -21,6 +21,7 @@ package org.jclouds.virtualbox.util; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import java.util.concurrent.ExecutionException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -37,6 +38,7 @@ import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.util.Throwables2; +import org.jclouds.virtualbox.functions.IpAddressesLoadingCache; import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.ISession; import org.virtualbox_4_1.LockType; @@ -69,12 +71,14 @@ public class MachineUtils { private final Supplier manager; private final Factory scriptRunner; + private final IpAddressesLoadingCache ipAddressesLoadingCache; @Inject - public MachineUtils(Supplier manager, RunScriptOnNode.Factory scriptRunner) { - super(); + public MachineUtils(Supplier manager, RunScriptOnNode.Factory scriptRunner, + IpAddressesLoadingCache ipAddressesLoadingCache) { this.manager = manager; this.scriptRunner = scriptRunner; + this.ipAddressesLoadingCache = ipAddressesLoadingCache; } public ListenableFuture runScriptOnNode(NodeMetadata metadata, Statement statement, @@ -207,9 +211,18 @@ public class MachineUtils { private ISession lockSession(String machineId, LockType type, int retries) { int count = 0; ISession session; + IMachine immutableMachine = manager.get().getVBox().findMachine(machineId); + + try { + session = manager.get().openMachineSession(immutableMachine); + if (session.getState().equals(SessionState.Locked)) + return checkNotNull(session, "session"); + } catch (Exception e) { + logger.debug("machine %s is not locked). Error: %s", immutableMachine.getName(), e.getMessage()); + } + while (true) { try { - IMachine immutableMachine = manager.get().getVBox().findMachine(machineId); session = manager.get().getSessionObject(); immutableMachine.lockMachine(session, type); break; @@ -219,13 +232,13 @@ public class MachineUtils { return null; } count++; - logger.warn(e, "Could not lock machine (try %d of %d). Error: %s", count, retries, e.getMessage()); + logger.debug("Could not lock machine (try %d of %d). Error: %s", count, retries, e.getMessage()); if (count == retries) { throw new RuntimeException(String.format("error locking %s with %s lock: %s", machineId, type, e.getMessage()), e); } try { - Thread.sleep(1000L); + Thread.sleep(count * 1000L); } catch (InterruptedException e1) { } } @@ -265,70 +278,24 @@ public class MachineUtils { || e.getMessage().contains("Could not find a registered machine with UUID {"); } - public String getIpAddressFromBridgedNIC(String machineName) { - String ip = ""; - int attempt = 0; - while (!isIpv4(ip) && attempt < 10) { - ip = this.lockSessionOnMachineAndApply(machineName, LockType.Shared, new Function() { - @Override - public String apply(ISession session) { - String ip = session.getMachine().getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP"); - return ip; - } - }); - attempt++; - long sleepTime = 1000 * attempt; - logger.debug("Instance %s is still not ready. Attempt n:%d. Sleeping for %d millisec", machineName, attempt, - sleepTime); - try { - Thread.sleep(sleepTime); - } catch (InterruptedException e) { - Throwables.propagate(e); - } + public String getIpAddressFromFirstNIC(String machineName) { + try { + return ipAddressesLoadingCache.get(machineName); + } catch (ExecutionException e) { + logger.error("Problem in using the ipAddressCache", e.getCause()); + throw Throwables.propagate(e); } - return ip; } + - private boolean isIpv4(String s) { - Pattern pattern = Pattern.compile(this.IP_V4_ADDRESS_PATTERN); + public static boolean isIpv4(String s) { + String IP_V4_ADDRESS_PATTERN = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$"; + Pattern pattern = Pattern.compile(IP_V4_ADDRESS_PATTERN); Matcher matcher = pattern.matcher(s); return matcher.matches(); } - public String getIpAddressFromHostOnlyNIC(String machineName) { - // TODO using a caching mechanism to avoid to call every time this vboxmanage api call - String currentIp = "", previousIp = "1.1.1.1"; - int attempt = 0, count = 0; - while(count < 5) { - currentIp = ""; - attempt = 0; - while (!isIpv4(currentIp) && attempt < 5) { - currentIp = this.lockSessionOnMachineAndApply(machineName, LockType.Shared, new Function() { - @Override - public String apply(ISession session) { - return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP"); - } - }); - attempt++; - } - if(previousIp.equals(currentIp)) { - count++; - delayer(500l * (count + 1)); - } else { - count = 0; - delayer(5000l); - } - previousIp = currentIp; - } - return currentIp; - } - - private void delayer(long millisec) { - try { - Thread.sleep(millisec); - } catch (InterruptedException e) { - Throwables.propagate(e); - } - } } diff --git a/labs/virtualbox/src/main/resources/default-images.yaml b/labs/virtualbox/src/main/resources/default-images.yaml index 84380c2b1f..c9ed61fe71 100644 --- a/labs/virtualbox/src/main/resources/default-images.yaml +++ b/labs/virtualbox/src/main/resources/default-images.yaml @@ -15,7 +15,7 @@ images: fb=false debconf/frontend=noninteractive keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false initrd=/install/initrd.gz -- - preseed_cfg: | + preseed_cfg: | ## Options to set on the command line d-i debian-installer/locale string en_US.utf8 d-i console-setup/ask_detect boolean false @@ -132,4 +132,91 @@ images: d-i pkgsel/update-policy select none # debconf-get-selections --install #Use mirror + choose-mirror-bin mirror/http/proxy string + - id: ubuntu-12.04.1-amd64 + name: ubuntu-12.04.1-server-amd64 + description: ubuntu 12.04.1 server (amd64) + os_arch: amd64 + os_family: ubuntu + os_description: ubuntu + os_version: 12.04.1 + os_64bit: true + iso: http://releases.ubuntu.com/12.04/ubuntu-12.04.1-server-amd64.iso + username: toor + credential: $user + keystroke_sequence: | + + /install/vmlinuz noapic preseed/url=http://10.0.2.2:8080/src/test/resources/preseed.cfg + debian-installer=en_US auto locale=en_US kbd-chooser/method=us + hostname=vmName + fb=false debconf/frontend=noninteractive + keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false + initrd=/install/initrd.gz -- + preseed_cfg: | + ## Options to set on the command line + d-i debian-installer/locale string en_US.utf8 + d-i console-setup/ask_detect boolean false + d-i console-setup/layout string USA + #d-i netcfg/get_hostname string dummy + d-i netcfg/get_hostname string unassigned-hostname + d-i netcfg/get_domain string unassigned-domain + # Continue without a default route + # Not working , specify a dummy in the DHCP + #d-i netcfg/no_default_route boolean + d-i time/zone string UTC + d-i clock-setup/utc-auto boolean true + d-i clock-setup/utc boolean true + d-i kbd-chooser/method select American English + d-i netcfg/wireless_wep string + d-i base-installer/kernel/override-image string linux-server + #d-i base-installer/kernel/override-image string linux-image-2.6.32-21-generic + # Choices: Dialog, Readline, Gnome, Kde, Editor, Noninteractive + d-i debconf debconf/frontend select Noninteractive + d-i pkgsel/install-language-support boolean false + tasksel tasksel/first multiselect standard, ubuntu-server + #d-i partman-auto/method string regular + d-i partman-auto/method string lvm + #d-i partman-auto/purge_lvm_from_device boolean true + d-i partman-lvm/confirm boolean true + d-i partman-lvm/device_remove_lvm boolean true + d-i partman-auto/choose_recipe select atomic + d-i partman/confirm_write_new_label boolean true + d-i partman/confirm_nooverwrite boolean true + d-i partman/choose_partition select finish + d-i partman/confirm boolean true + #http://ubuntu-virginia.ubuntuforums.org/showthread.php?p=9626883 + #Message: "write the changes to disk and configure lvm preseed" + #http://serverfault.com/questions/189328/ubuntu-kickstart-installation-using-lvm-waits-for-input + #preseed partman-lvm/confirm_nooverwrite boolean true + # Write the changes to disks and configure LVM? + d-i partman-lvm/confirm boolean true + d-i partman-lvm/confirm_nooverwrite boolean true + d-i partman-auto-lvm/guided_size string max + ## Default user, we can get away with a recipe to change this + d-i passwd/user-fullname string toor + d-i passwd/username string toor + d-i passwd/user-password password password + d-i passwd/user-password-again password password + d-i user-setup/encrypt-home boolean false + d-i user-setup/allow-password-weak boolean true + ## minimum is ssh and ntp + # Individual additional packages to install + d-i pkgsel/include string openssh-server ntp + # Whether to upgrade packages after debootstrap. + # Allowed values: none, safe-upgrade, full-upgrade + d-i pkgsel/upgrade select full-upgrade + d-i grub-installer/only_debian boolean true + d-i grub-installer/with_other_os boolean true + d-i finish-install/reboot_in_progress note + #For the update + d-i pkgsel/update-policy select none + # debconf-get-selections --install + #Use mirror + #d-i apt-setup/use_mirror boolean true + #d-i mirror/country string manual + #choose-mirror-bin mirror/protocol string http + #choose-mirror-bin mirror/http/hostname string 192.168.4.150 + #choose-mirror-bin mirror/http/directory string /ubuntu + #choose-mirror-bin mirror/suite select maverick + #d-i debian-installer/allow_unauthenticated string true choose-mirror-bin mirror/http/proxy string \ No newline at end of file diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java index b2c2c45213..4dbe57877d 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java @@ -119,7 +119,7 @@ public class BaseVirtualBoxClientLiveTest extends BaseComputeServiceContextLiveT protected LoadingCache mastersCache; private final ExecutorService singleThreadExec = MoreExecutors.sameThreadExecutor(); - private String masterVmName; + private String masterName; @Override @@ -133,13 +133,13 @@ public class BaseVirtualBoxClientLiveTest extends BaseComputeServiceContextLiveT public void setupContext() { super.setupContext(); view.utils().injector().injectMembers(this); - + // try and get a master from the cache, this will initialize the config/download isos and // prepare everything IF a master is not available, subsequent calls should be pretty fast Template template = view.getComputeService().templateBuilder().build(); checkNotNull(mastersCache.apply(template.getImage())); - masterVmName = VIRTUALBOX_IMAGE_PREFIX + template.getImage().getId(); + masterName = VIRTUALBOX_IMAGE_PREFIX + template.getImage().getId(); isosDir = workingDir + File.separator + "isos"; hostVersion = Iterables.get(Splitter.on('r').split(view.utils().injector().getInstance(Key.get(String.class, BuildVersion.class))), 0); @@ -173,8 +173,6 @@ public class BaseVirtualBoxClientLiveTest extends BaseComputeServiceContextLiveT } public MasterSpec getMasterSpecForTest() { - String masterName = "jclouds-image-0x0-" + template.getImageId(); - StorageController ideController = StorageController .builder() .name("IDE Controller") @@ -220,7 +218,7 @@ public class BaseVirtualBoxClientLiveTest extends BaseComputeServiceContextLiveT protected void destroyMaster() { if (System.getProperty(DONT_DESTROY_MASTER) == null || !Boolean.parseBoolean(System.getProperty(DONT_DESTROY_MASTER))) { - undoVm(masterVmName); + undoVm(masterName); } } diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/PreseedCfgServerTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/PreseedCfgServerTest.java index 28c6001f9e..ad71c22e3f 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/PreseedCfgServerTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/PreseedCfgServerTest.java @@ -20,7 +20,6 @@ package org.jclouds.virtualbox; import static org.testng.Assert.assertEquals; -import java.io.File; import java.net.URI; import java.net.URL; import java.util.Map; diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java index cf3969d5bd..7cdee2d010 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java @@ -51,7 +51,7 @@ public class VirtualBoxComputeServiceAdapterLiveTest extends BaseVirtualBoxClien @Test public void testCreatedNodeHasExpectedNameAndWeCanConnectViaSsh() { String group = "foo"; - String name = "foo-ef4"; + String name = "foo-ef9"; Template template = view.getComputeService().templateBuilder().build(); machine = adapter.createNodeWithGroupEncodedIntoName(group, name, template); assertTrue(machine.getNode().getName().contains(group)); @@ -60,7 +60,7 @@ public class VirtualBoxComputeServiceAdapterLiveTest extends BaseVirtualBoxClien doConnectViaSsh(machine.getNode(), prioritizeCredentialsFromTemplate.apply(template, machine.getCredentials())); } - protected void doConnectViaSsh(IMachine machine, LoginCredentials creds) { + protected void doConnectViaSsh(IMachine machine, LoginCredentials creds) { SshClient ssh = view.utils().injector().getInstance(IMachineToSshClient.class).apply(machine); try { ssh.connect(); diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxExperimentLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxExperimentLiveTest.java index b2929b4a09..fa5e67a83f 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxExperimentLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxExperimentLiveTest.java @@ -36,7 +36,6 @@ import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; -import org.jclouds.scriptbuilder.statements.login.AdminAccess; import org.jclouds.ssh.SshClient; import org.jclouds.sshj.config.SshjSshClientModule; import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest; @@ -69,10 +68,10 @@ public class VirtualBoxExperimentLiveTest extends BaseVirtualBoxClientLiveTest { @Test public void testLaunchCluster() throws RunNodesException { - int numNodes = 2; + int numNodes = 3; final String clusterName = "test-launch-cluster"; Set nodes = context.getComputeService().createNodesInGroup(clusterName, numNodes, - TemplateOptions.Builder.runScript(AdminAccess.standard())); + TemplateOptions.Builder.overrideLoginUser("toor")); //TODO runScript(AdminAccess.standard())); assertEquals(numNodes, nodes.size(), "wrong number of nodes"); for (NodeMetadata node : nodes) { assertTrue(node.getGroup().equals("test-launch-cluster")); diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/extensions/VirtualBoxImageExtensionLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/extensions/VirtualBoxImageExtensionLiveTest.java index 31a416b4a7..575a182944 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/extensions/VirtualBoxImageExtensionLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/extensions/VirtualBoxImageExtensionLiveTest.java @@ -19,6 +19,9 @@ package org.jclouds.virtualbox.compute.extensions; +import java.util.concurrent.ExecutionException; + +import org.jclouds.compute.RunNodesException; import org.jclouds.compute.extensions.internal.BaseImageExtensionLiveTest; import org.jclouds.sshj.config.SshjSshClientModule; import org.testng.annotations.Test; @@ -28,6 +31,22 @@ import com.google.inject.Module; @Test(groups = "live", singleThreaded = true, testName = "VirtualBoxImageExtensionLiveTest") public class VirtualBoxImageExtensionLiveTest extends BaseImageExtensionLiveTest { + @Override + public void testDeleteImage() { + // TODO + } + + @Override + public void testCreateImage() throws RunNodesException, + InterruptedException, ExecutionException { + // TODO + } + + @Override + public void testSpawnNodeFromImage() throws RunNodesException { + // TODO + } + public VirtualBoxImageExtensionLiveTest() { provider = "virtualbox"; } diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java index c5576209d3..bd25a24cff 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java @@ -24,14 +24,18 @@ import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE; import static org.testng.Assert.assertTrue; +import java.net.URI; import java.util.Map; +import javax.inject.Inject; + import org.jclouds.compute.config.BaseComputeServiceContextModule; import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.config.ValueOfConfigurationKeyOrNull; import org.jclouds.json.Json; import org.jclouds.json.config.GsonModule; +import org.jclouds.location.Provider; import org.jclouds.ssh.SshClient; import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest; import org.jclouds.virtualbox.domain.CloneSpec; @@ -49,13 +53,13 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import org.virtualbox_4_1.CleanupMode; import org.virtualbox_4_1.IMachine; -import org.virtualbox_4_1.ISession; import org.virtualbox_4_1.NetworkAttachmentType; import org.virtualbox_4_1.StorageBus; import com.google.common.base.CaseFormat; import com.google.common.base.Function; import com.google.common.base.Predicate; +import com.google.common.base.Supplier; import com.google.common.collect.ImmutableSet; import com.google.inject.Guice; import com.google.inject.Injector; @@ -76,44 +80,11 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest { private MasterSpec machineSpec; private String instanceName; - - /* - @Override - @BeforeClass(groups = "live") - public void setupClient() { - super.setupClient(); - this.vmName = VIRTUALBOX_IMAGE_PREFIX - + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName()); - - HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk(vmName)).autoDelete(true).controllerPort(0) - .deviceSlot(1).build(); - StorageController ideController = StorageController.builder().name("IDE Controller").bus(StorageBus.IDE) - .attachISO(0, 0, operatingSystemIso).attachHardDisk(hardDisk).attachISO(1, 1, guestAdditionsIso).build(); - vmSpecification = VmSpec.builder().id(vmName).name(vmName).memoryMB(512).osTypeId("").controller(ideController) - .forceOverwrite(true).cleanUpMode(CleanupMode.Full).build(); - - injector = context.utils().injector(); - Function configProperties = injector.getInstance(ValueOfConfigurationKeyOrNull.class); - - NetworkAdapter natAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT) - .tcpRedirectRule("127.0.0.1", 2222, "", 22).build(); - - NetworkInterfaceCard networkInterfaceCard1 = NetworkInterfaceCard.builder().slot(0l) - .addNetworkAdapter(natAdapter).build(); - - NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard1).build(); - - masterSpec = MasterSpec - .builder() - .vm(vmSpecification) - .iso(IsoSpec - .builder() - .sourcePath(operatingSystemIso) - .installationScript( - configProperties.apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE).replace("HOSTNAME", - vmSpecification.getVmName())).build()).network(networkSpec).build(); - }*/ + @Inject + @Provider + protected Supplier providerSupplier; + @Override @BeforeClass(groups = "live") public void setupContext() { @@ -142,11 +113,10 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest { configProperties.apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE).replace("HOSTNAME", instanceVmSpec.getVmName())).build(); - NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT) - .tcpRedirectRule("127.0.0.1", 2222, "", 22).build(); - NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter) + NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.HostOnly) .build(); - + NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter) + .addHostInterfaceName("vboxnet0").slot(0L).build(); NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build(); machineSpec = MasterSpec.builder().iso(isoSpec).vm(instanceVmSpec).network(networkSpec).build(); } @@ -164,12 +134,7 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest { checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh", machine.getName()); - String version = machineUtils.sharedLockMachineAndApplyToSession(machine.getName(), new Function() { - @Override - public String apply(ISession session) { - return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestAdd/Version"); - } - }); + String version = machine.getGuestPropertyValue("/VirtualBox/GuestAdd/Version"); assertTrue(version != null && !version.isEmpty()); } finally { @@ -193,7 +158,6 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest { Injector injector = view.utils().injector(); return injector.getInstance(CreateAndInstallVm.class).apply(masterSpecForTest); } catch (IllegalStateException e) { - // already created return manager.get().getVBox().findMachine(masterSpecForTest.getVmSpec().getVmId()); } } diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java index b3b31da7d1..22016b2c20 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java @@ -64,7 +64,7 @@ public class StartVBoxIfNotAlreadyRunningLiveTest { replay(manager, runScriptOnNodeFactory, client); new StartVBoxIfNotAlreadyRunning((Function) Functions.constant(manager), runScriptOnNodeFactory, client, - Suppliers.ofInstance(host), Suppliers.ofInstance(provider)).start(); + Suppliers.ofInstance(host), Suppliers.ofInstance(provider), null).start(); verify(manager, runScriptOnNodeFactory, client); @@ -84,26 +84,26 @@ public class StartVBoxIfNotAlreadyRunningLiveTest { expect(client.seconds(3)).andReturn(client); expect(client.apply(HostAndPort.fromParts(provider.getHost(), provider.getPort()))).andReturn(false).once().andReturn(true).once(); - expect( - runScriptOnNodeFactory.create(host, Statements.exec("VBoxManage setproperty websrvauthlibrary null"), + expect(runScriptOnNodeFactory.create(host, + Statements.exec("VBoxManage setproperty websrvauthlibrary null"), runAsRoot(false).wrapInInitScript(false))).andReturn(runScriptOnNode); expect(runScriptOnNode.init()).andReturn(runScriptOnNode); expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0)); - expect( - runScriptOnNodeFactory.create(host, Statements.exec("vboxwebsrv -t 10000 -v -b"), runAsRoot(false) - .wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv"))).andReturn( - runScriptOnNode); + expect(runScriptOnNodeFactory.create(host, + Statements.exec("vboxwebsrv -t 10000 -v -b -H localhost"), runAsRoot(false) + .wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv"))) + .andReturn(runScriptOnNode); expect(runScriptOnNode.init()).andReturn(runScriptOnNode); expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0)); - manager.connect(provider.toASCIIString(), "", ""); + expectLastCall().anyTimes(); replay(manager, runScriptOnNodeFactory, runScriptOnNode, client); new StartVBoxIfNotAlreadyRunning((Function) Functions.constant(manager), runScriptOnNodeFactory, client, - Suppliers.ofInstance(host), Suppliers.ofInstance(provider)); + Suppliers.ofInstance(host), Suppliers.ofInstance(provider), null); + verify(manager, runScriptOnNodeFactory, runScriptOnNode, client); - } } \ No newline at end of file diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstallerLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstallerLiveTest.java index 8c79df17fb..b21ce39586 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstallerLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstallerLiveTest.java @@ -24,9 +24,6 @@ import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE; import static org.testng.Assert.assertTrue; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import org.jclouds.config.ValueOfConfigurationKeyOrNull; import org.jclouds.ssh.SshClient; import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest; @@ -42,11 +39,12 @@ import org.jclouds.virtualbox.domain.VmSpec; import org.jclouds.virtualbox.functions.CloneAndRegisterMachineFromIMachineIfNotAlreadyExists; import org.jclouds.virtualbox.functions.CreateAndInstallVm; import org.jclouds.virtualbox.functions.IMachineToSshClient; +import org.jclouds.virtualbox.functions.IpAddressesLoadingCache; +import org.jclouds.virtualbox.util.MachineUtils; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import org.virtualbox_4_1.CleanupMode; import org.virtualbox_4_1.IMachine; -import org.virtualbox_4_1.ISession; import org.virtualbox_4_1.NetworkAttachmentType; import org.virtualbox_4_1.StorageBus; @@ -67,6 +65,7 @@ public class GuestAdditionsInstallerLiveTest extends BaseVirtualBoxClientLiveTes private Predicate sshResponds; private MasterSpec machineSpec; + private IpAddressesLoadingCache ipAddressesLoadingCache; @Override @BeforeClass(groups = "live") @@ -118,21 +117,10 @@ public class GuestAdditionsInstallerLiveTest extends BaseVirtualBoxClientLiveTes sshResponds = injector.getInstance(SshResponds.class); checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh", machine.getName()); + ipAddressesLoadingCache = injector.getInstance(IpAddressesLoadingCache.class); + + assertTrue(MachineUtils.isIpv4(ipAddressesLoadingCache.apply(machine.getName()))); - assertTrue(machineUtils.sharedLockMachineAndApplyToSession(machine.getName(), - new Function() { - @Override - public Boolean apply(ISession session) { - String s = session.getMachine().getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP"); - return isIpv4(s); - } - - private boolean isIpv4(String s) { - Pattern pattern = Pattern.compile(machineUtils.IP_V4_ADDRESS_PATTERN); - Matcher matcher = pattern.matcher(s); - return matcher.matches(); - } - })); } finally { for (String vmNameOrId : ImmutableSet.of(machine.getName())) { machineController.ensureMachineHasPowerDown(vmNameOrId); diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/util/MachineControllerLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/util/MachineControllerLiveTest.java index 2291d625c7..6b15823488 100644 --- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/util/MachineControllerLiveTest.java +++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/util/MachineControllerLiveTest.java @@ -77,21 +77,25 @@ public class MachineControllerLiveTest extends BaseVirtualBoxClientLiveTest { .cleanUpMode(CleanupMode.Full).controller(ideController).forceOverwrite(true).build(); Injector injector = view.utils().injector(); - Function configProperties = injector.getInstance(ValueOfConfigurationKeyOrNull.class); + Function configProperties = injector + .getInstance(ValueOfConfigurationKeyOrNull.class); IsoSpec isoSpec = IsoSpec - .builder() - .sourcePath(operatingSystemIso) - .installationScript( - configProperties.apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE).replace("HOSTNAME", - instanceVmSpec.getVmName())).build(); + .builder() + .sourcePath(operatingSystemIso) + .installationScript( + configProperties.apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE) + .replace("HOSTNAME", instanceVmSpec.getVmName())) + .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(networkInterfaceCard).build(); - machineSpec = MasterSpec.builder().iso(isoSpec).vm(instanceVmSpec).network(networkSpec).build(); + NetworkAdapter networkAdapter = NetworkAdapter.builder() + .networkAttachmentType(NetworkAttachmentType.HostOnly).build(); + NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard + .builder().addNetworkAdapter(networkAdapter) + .addHostInterfaceName("vboxnet0").slot(0L).build(); + NetworkSpec networkSpec = NetworkSpec.builder() + .addNIC(networkInterfaceCard).build(); + machineSpec = MasterSpec.builder().iso(isoSpec).vm(instanceVmSpec) + .network(networkSpec).build(); } @Test @@ -106,8 +110,8 @@ public class MachineControllerLiveTest extends BaseVirtualBoxClientLiveTest { @Test(dependsOnMethods="testEnsureMachineisLaunchedAndSessionIsUnlocked") public void testEnsureMachineCanBePoweredOffMoreThanOneTimeAndSessionIsUnlocked() { ISession cloneMachineSession = machineController.ensureMachineHasPowerDown(instanceName); - cloneMachineSession = machineController.ensureMachineHasPowerDown(instanceName); - assertTrue(cloneMachineSession.getState() == SessionState.Unlocked); + SessionState state = cloneMachineSession.getState(); + assertTrue(state.equals(SessionState.Unlocked)); } private IMachine cloneFromMaster() { diff --git a/labs/virtualbox/src/test/resources/default-images.yaml b/labs/virtualbox/src/test/resources/default-images.yaml index 4efa20d277..fddcff3c4a 100644 --- a/labs/virtualbox/src/test/resources/default-images.yaml +++ b/labs/virtualbox/src/test/resources/default-images.yaml @@ -15,7 +15,7 @@ images: fb=false debconf/frontend=noninteractive keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false initrd=/install/initrd.gz -- - preseed_cfg: | + preseed_cfg: | ## Options to set on the command line d-i debian-installer/locale string en_US.utf8 d-i console-setup/ask_detect boolean false @@ -66,7 +66,7 @@ images: # debconf-get-selections --install #Use mirror choose-mirror-bin mirror/http/proxy string - - id: test-ubuntu-11.10-i386 + - id: ubuntu-11.10-i386 name: ubuntu-11.10-server-i386 description: ubuntu 11.10 server (i386) os_arch: x86 @@ -132,4 +132,90 @@ images: d-i pkgsel/update-policy select none # debconf-get-selections --install #Use mirror + choose-mirror-bin mirror/http/proxy string + - id: ubuntu-12.04.1-amd64 + name: ubuntu-12.04.1-server-amd64 + description: ubuntu 12.04.1 server (amd64) + os_arch: amd64 + os_family: ubuntu + os_description: ubuntu + os_version: 12.04.1 + os_64bit: true + iso: http://releases.ubuntu.com/12.04/ubuntu-12.04.1-server-amd64.iso + iso_md5: a8c667e871f48f3a662f3fbf1c3ddb17 + keystroke_sequence: | + + /install/vmlinuz noapic preseed/url=http://10.0.2.2:8080/src/test/resources/preseed.cfg + debian-installer=en_US auto locale=en_US kbd-chooser/method=us + hostname=vmName + fb=false debconf/frontend=noninteractive + keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false + initrd=/install/initrd.gz -- + preseed_cfg: | + ## Options to set on the command line + d-i debian-installer/locale string en_US.utf8 + d-i console-setup/ask_detect boolean false + d-i console-setup/layout string USA + #d-i netcfg/get_hostname string dummy + d-i netcfg/get_hostname string unassigned-hostname + d-i netcfg/get_domain string unassigned-domain + # Continue without a default route + # Not working , specify a dummy in the DHCP + #d-i netcfg/no_default_route boolean + d-i time/zone string UTC + d-i clock-setup/utc-auto boolean true + d-i clock-setup/utc boolean true + d-i kbd-chooser/method select American English + d-i netcfg/wireless_wep string + d-i base-installer/kernel/override-image string linux-server + #d-i base-installer/kernel/override-image string linux-image-2.6.32-21-generic + # Choices: Dialog, Readline, Gnome, Kde, Editor, Noninteractive + d-i debconf debconf/frontend select Noninteractive + d-i pkgsel/install-language-support boolean false + tasksel tasksel/first multiselect standard, ubuntu-server + #d-i partman-auto/method string regular + d-i partman-auto/method string lvm + #d-i partman-auto/purge_lvm_from_device boolean true + d-i partman-lvm/confirm boolean true + d-i partman-lvm/device_remove_lvm boolean true + d-i partman-auto/choose_recipe select atomic + d-i partman/confirm_write_new_label boolean true + d-i partman/confirm_nooverwrite boolean true + d-i partman/choose_partition select finish + d-i partman/confirm boolean true + #http://ubuntu-virginia.ubuntuforums.org/showthread.php?p=9626883 + #Message: "write the changes to disk and configure lvm preseed" + #http://serverfault.com/questions/189328/ubuntu-kickstart-installation-using-lvm-waits-for-input + #preseed partman-lvm/confirm_nooverwrite boolean true + # Write the changes to disks and configure LVM? + d-i partman-lvm/confirm boolean true + d-i partman-lvm/confirm_nooverwrite boolean true + d-i partman-auto-lvm/guided_size string max + ## Default user, we can get away with a recipe to change this + d-i passwd/user-fullname string toor + d-i passwd/username string toor + d-i passwd/user-password password password + d-i passwd/user-password-again password password + d-i user-setup/encrypt-home boolean false + d-i user-setup/allow-password-weak boolean true + ## minimum is ssh and ntp + # Individual additional packages to install + d-i pkgsel/include string openssh-server ntp + # Whether to upgrade packages after debootstrap. + # Allowed values: none, safe-upgrade, full-upgrade + d-i pkgsel/upgrade select full-upgrade + d-i grub-installer/only_debian boolean true + d-i grub-installer/with_other_os boolean true + d-i finish-install/reboot_in_progress note + #For the update + d-i pkgsel/update-policy select none + # debconf-get-selections --install + #Use mirror + #d-i apt-setup/use_mirror boolean true + #d-i mirror/country string manual + #choose-mirror-bin mirror/protocol string http + #choose-mirror-bin mirror/http/hostname string 192.168.4.150 + #choose-mirror-bin mirror/http/directory string /ubuntu + #choose-mirror-bin mirror/suite select maverick + #d-i debian-installer/allow_unauthenticated string true choose-mirror-bin mirror/http/proxy string \ No newline at end of file