Added support for changing the IP of a VBox Node at runtime. Added use of CacheLoader for the VBox ComputeService.

This commit is contained in:
Mattias Holmqvist 2011-09-24 02:04:44 +02:00
parent c46c0b4c47
commit fc5d172523
21 changed files with 621 additions and 234 deletions

View File

@ -21,5 +21,17 @@
package org.jclouds.virtualbox;
import org.virtualbox_4_1.VirtualBoxManager;
public class VirtualBox {
private VirtualBoxManager manager;
public VirtualBox() {
this.manager = VirtualBoxManager.createInstance("");
}
public VirtualBoxManager manager() {
return manager;
}
}

View File

@ -24,6 +24,7 @@ package org.jclouds.virtualbox;
import org.jclouds.PropertiesBuilder;
import org.jclouds.virtualbox.config.VirtualBoxConstants;
import java.io.File;
import java.util.Properties;
import static org.jclouds.Constants.*;
@ -51,6 +52,22 @@ public class VirtualBoxPropertiesBuilder extends PropertiesBuilder {
properties.put(PROPERTY_ENDPOINT, "http://localhost:18083/");
properties.put(VirtualBoxConstants.VIRTUALBOX_PRESEED_URL, "http://dl.dropbox.com/u/693111/preseed.cfg");
properties.put(VirtualBoxConstants.VIRTUALBOX_SNAPSHOT_DESCRIPTION, "jclouds-virtualbox-snaphot");
properties.put(VirtualBoxConstants.VIRTUALBOX_HOSTNAME, "jclouds-virtualbox-kickstart-admin");
properties.put(VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE, "<Esc><Esc><Enter> "
+ "/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="
+ properties.get(VirtualBoxConstants.VIRTUALBOX_HOSTNAME)
+ " "
+ "fb=false debconf/frontend=noninteractive "
+ "keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false "
+ "initrd=/install/initrd.gz -- <Enter>");
properties.put(VirtualBoxConstants.VIRTUALBOX_WORKINGDIR, System.getProperty("user.home")
+ File.separator
+ System.getProperty("test.virtualbox.workingDir",
"jclouds-virtualbox-test"));
// TODO: Add more properties and use the wired properties from test code.
return properties;
}

View File

@ -0,0 +1,107 @@
/*
* *
* * 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.compute;
import com.google.common.base.Function;
import com.google.common.cache.CacheLoader;
import org.jclouds.byon.Node;
import org.jclouds.compute.domain.OsFamily;
import org.virtualbox_4_1.IGuestOSType;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.VirtualBoxManager;
import javax.inject.Inject;
import java.net.URI;
import java.net.URISyntaxException;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.*;
/**
* Loads a node from a VirtualBox IMachine
*
* @author Mattias Holmqvist
*/
public class LoadMachineFromVirtualBox extends CacheLoader<String, Node> {
private VirtualBoxManager manager;
private Function<IMachine, String> iMachineToIpAddress;
@Inject
public LoadMachineFromVirtualBox(VirtualBoxManager manager, Function<IMachine, String> iMachineToIpAddress) {
this.manager = manager;
this.iMachineToIpAddress = iMachineToIpAddress;
}
@Override
public Node load(final String id) throws Exception {
if (id.equals("host")) {
final Node hostNode = Node.builder().id("host")
.name("host installing virtualbox")
.hostname("localhost")
.osFamily(OsFamily.LINUX.toString())
.osDescription(System.getProperty("os.name"))
.osVersion(System.getProperty("os.version"))
.group("ssh")
.username(System.getProperty("user.name"))
.credentialUrl(privateKeyFile())
.build();
return hostNode;
}
final IMachine machine = manager.getVBox().findMachine(id);
final String ipAddress = iMachineToIpAddress.apply(machine);
final String osTypeId = machine.getOSTypeId();
final IGuestOSType guestOSType = manager.getVBox().getGuestOSType(osTypeId);
final Node node = Node.builder()
.id(machine.getId())
.name(machine.getName())
.description(machine.getDescription())
.loginPort(22)
.group(System.getProperty(VIRTUALBOX_MACHINE_GROUP))
.username(System.getProperty(VIRTUALBOX_MACHINE_USERNAME))
.credential(System.getProperty(VIRTUALBOX_MACHINE_CREDENTIAL))
.sudoPassword(System.getProperty(VIRTUALBOX_MACHINE_CREDENTIAL))
.locationId(System.getProperty(VIRTUALBOX_MACHINE_LOCATION))
.os64Bit(guestOSType.getIs64Bit())
.osArch(guestOSType.getDescription())
.osFamily(guestOSType.getFamilyDescription())
.osVersion(guestOSType.getId())
.osDescription(guestOSType.getDescription())
.hostname(ipAddress)
.build();
return node;
}
private static URI privateKeyFile() {
try {
return new URI("file://" + System.getProperty("user.home") + "/.ssh/id_rsa");
} catch (URISyntaxException e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -21,28 +21,19 @@
package org.jclouds.virtualbox.compute;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collections;
import java.util.Map;
import javax.inject.Inject;
import com.google.common.base.Throwables;
import com.google.inject.Singleton;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.domain.Template;
import org.jclouds.domain.Credentials;
import org.jclouds.virtualbox.domain.Host;
import org.jclouds.virtualbox.domain.Image;
import org.jclouds.virtualbox.domain.VMSpec;
import org.virtualbox_4_1.CleanupMode;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.SessionState;
import org.virtualbox_4_1.VirtualBoxManager;
import org.virtualbox_4_1.*;
import com.google.common.base.Throwables;
import com.google.inject.Singleton;
import javax.inject.Inject;
import java.util.Collections;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Defines the connection between the {@link org.virtualbox_4_1.VirtualBoxManager} implementation and the jclouds
@ -51,7 +42,7 @@ import com.google.inject.Singleton;
* @author Mattias Holmqvist, Andrea Turli
*/
@Singleton
public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IMachine, VMSpec, Image, Host> {
public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IMachine, IMachine, IMachine, Host> {
private final VirtualBoxManager manager;
@ -71,12 +62,12 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
}
@Override
public Iterable<VMSpec> listHardwareProfiles() {
public Iterable<IMachine> listHardwareProfiles() {
return Collections.emptyList();
}
@Override
public Iterable<Image> listImages() {
public Iterable<IMachine> listImages() {
return Collections.emptyList();
}

View File

@ -21,41 +21,39 @@
package org.jclouds.virtualbox.config;
import java.net.URI;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Injector;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
import org.jclouds.Constants;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.*;
import org.jclouds.domain.Location;
import org.jclouds.location.Provider;
import org.jclouds.location.suppliers.OnlyLocationOrFirstZone;
import org.jclouds.virtualbox.compute.VirtualBoxComputeServiceAdapter;
import org.jclouds.virtualbox.domain.Host;
import org.jclouds.virtualbox.domain.Image;
import org.jclouds.virtualbox.domain.VMSpec;
import org.jclouds.virtualbox.functions.HostToLocation;
import org.jclouds.virtualbox.functions.IMachineToHardware;
import org.jclouds.virtualbox.functions.IMachineToImage;
import org.jclouds.virtualbox.functions.IMachineToNodeMetadata;
import org.jclouds.virtualbox.functions.ImageToImage;
import org.jclouds.virtualbox.functions.VMSpecToHardware;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.MachineState;
import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.inject.Injector;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
import javax.inject.Named;
import javax.inject.Singleton;
import java.net.URI;
import java.util.Map;
/**
* @author Mattias Holmqvist, Andrea Turli
*/
public class VirtualBoxComputeServiceContextModule extends ComputeServiceAdapterContextModule<VirtualBoxManager, VirtualBoxManager, IMachine, VMSpec, Image, Host> {
public class VirtualBoxComputeServiceContextModule extends ComputeServiceAdapterContextModule<VirtualBoxManager, VirtualBoxManager, IMachine, IMachine, IMachine, Host> {
public VirtualBoxComputeServiceContextModule() {
super(VirtualBoxManager.class, VirtualBoxManager.class);
@ -73,16 +71,16 @@ public class VirtualBoxComputeServiceContextModule extends ComputeServiceAdapter
@Override
protected void configure() {
super.configure();
bind(new TypeLiteral<ComputeServiceAdapter<IMachine, VMSpec, Image, Host>>() {
bind(new TypeLiteral<ComputeServiceAdapter<IMachine, IMachine, IMachine, Host>>() {
}).to(VirtualBoxComputeServiceAdapter.class);
bind(new TypeLiteral<Function<IMachine, NodeMetadata>>() {
}).to(IMachineToNodeMetadata.class);
bind(new TypeLiteral<Function<Host, Location>>() {
}).to(HostToLocation.class);
bind(new TypeLiteral<Function<VMSpec, org.jclouds.compute.domain.Hardware>>() {
}).to(VMSpecToHardware.class);
bind(new TypeLiteral<Function<Image, org.jclouds.compute.domain.Image>>() {
}).to(ImageToImage.class);
bind(new TypeLiteral<Function<IMachine, Hardware>>() {
}).to(IMachineToHardware.class);
bind(new TypeLiteral<Function<IMachine, Image>>() {
}).to(IMachineToImage.class);
bind(new TypeLiteral<Supplier<Location>>() {
}).to(OnlyLocationOrFirstZone.class);
}
@ -91,4 +89,34 @@ public class VirtualBoxComputeServiceContextModule extends ComputeServiceAdapter
protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) {
return template.osFamily(OsFamily.UBUNTU).os64Bit(false).osVersionMatches("11.04-server");
}
@VisibleForTesting
public static final Map<MachineState, NodeState> machineToNodeState = ImmutableMap
.<MachineState, NodeState>builder()
.put(MachineState.Running, NodeState.RUNNING)
.put(MachineState.PoweredOff, NodeState.SUSPENDED)
.put(MachineState.DeletingSnapshot, NodeState.PENDING)
.put(MachineState.DeletingSnapshotOnline, NodeState.PENDING)
.put(MachineState.DeletingSnapshotPaused, NodeState.PENDING)
.put(MachineState.FaultTolerantSyncing, NodeState.PENDING)
.put(MachineState.LiveSnapshotting, NodeState.PENDING)
.put(MachineState.SettingUp, NodeState.PENDING)
.put(MachineState.Starting, NodeState.PENDING)
.put(MachineState.Stopping, NodeState.PENDING)
.put(MachineState.Restoring, NodeState.PENDING)
// TODO What to map these states to?
.put(MachineState.FirstOnline, NodeState.PENDING)
.put(MachineState.FirstTransient, NodeState.PENDING)
.put(MachineState.LastOnline, NodeState.PENDING)
.put(MachineState.LastTransient, NodeState.PENDING)
.put(MachineState.Teleported, NodeState.PENDING)
.put(MachineState.TeleportingIn, NodeState.PENDING)
.put(MachineState.TeleportingPausedVM, NodeState.PENDING)
.put(MachineState.Aborted, NodeState.ERROR)
.put(MachineState.Stuck, NodeState.ERROR)
.put(MachineState.Null, NodeState.UNRECOGNIZED).build();
}

View File

@ -33,5 +33,21 @@ public interface VirtualBoxConstants {
public static final String VIRTUALBOX_SNAPSHOT_DESCRIPTION = "jclouds.virtualbox.snapshotDescription";
public static final String VIRTUALBOX_INSTALLATION_KEY_SEQUENCE = "jclouds.virtualbox.installationkeysequence";
public static final String VIRTUALBOX_HOSTNAME = "jclouds.virtualbox.hostname";
public static final String VIRTUALBOX_WORKINGDIR = "jclouds.virtualbox.workingdir";
public static final String VIRTUALBOX_ISOFILE = "jclouds.virtualbox.isofile";
public static final String VIRTUALBOX_MACHINE_GROUP = "jclouds.virtualbox.machinegroup";
public static final String VIRTUALBOX_MACHINE_USERNAME = "jclouds.virtualbox.username";
public static final String VIRTUALBOX_MACHINE_CREDENTIAL = "jclouds.virtualbox.credential";
public static final String VIRTUALBOX_MACHINE_LOCATION = "jclouds.virtualbox.location";
public static final String VIRTUALBOX_HOST_ID = "jclouds.virtualbox.hostid";
}

View File

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

View File

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

View File

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

View File

@ -22,15 +22,35 @@
package org.jclouds.virtualbox.functions;
import com.google.common.base.Function;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.virtualbox.domain.VMSpec;
import org.jclouds.virtualbox.VirtualBox;
import org.virtualbox_4_1.IGuestOSType;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.VirtualBoxManager;
public class VMSpecToHardware implements Function<VMSpec, org.jclouds.compute.domain.Hardware> {
import javax.inject.Inject;
public class IMachineToHardware implements Function<IMachine, Hardware> {
private VirtualBox vbox;
@Inject
public IMachineToHardware(VirtualBox vbox) {
this.vbox = vbox;
}
@Override
public org.jclouds.compute.domain.Hardware apply(@Nullable VMSpec input) {
public Hardware apply(@Nullable IMachine vm) {
String osTypeId = vm.getOSTypeId();
IGuestOSType guestOSType = vbox.manager().getVBox().getGuestOSType(osTypeId);
Boolean is64Bit = guestOSType.getIs64Bit();
HardwareBuilder hardwareBuilder = new HardwareBuilder();
return hardwareBuilder.build();
hardwareBuilder.ids(vm.getId());
vm.getSessionPid();
hardwareBuilder.is64Bit(is64Bit);
return null;
}
}

View File

@ -22,14 +22,18 @@
package org.jclouds.virtualbox.functions;
import com.google.common.base.Function;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageBuilder;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.virtualbox.domain.Image;
import org.virtualbox_4_1.IMachine;
public class IMachineToImage implements Function<IMachine, Image> {
public class ImageToImage implements Function<Image, org.jclouds.compute.domain.Image> {
@Override
public org.jclouds.compute.domain.Image apply(@Nullable Image from) {
public Image apply(@Nullable IMachine vm) {
ImageBuilder imageBuilder = new ImageBuilder();
return imageBuilder.build();
imageBuilder.ids(vm.getId());
return null;
}
}

View File

@ -0,0 +1,91 @@
/*
* *
* * 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 com.google.common.base.Function;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.virtualbox.config.VirtualBoxConstants;
import org.virtualbox_4_1.IGuestOSType;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.VirtualBoxManager;
import javax.annotation.Nullable;
import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
public class IMachineToIpAddress implements Function<IMachine, String> {
private VirtualBoxManager manager;
private ComputeService computeService;
public IMachineToIpAddress(VirtualBoxManager manager, ComputeService computeService) {
this.manager = manager;
this.computeService = computeService;
}
@Override
public String apply(@Nullable IMachine machine) {
String macAddress = machine.getNetworkAdapter(0l).getMACAddress();
int offset = 0, step = 2;
for (int j = 1; j <= 5; j++) {
macAddress = new StringBuffer(macAddress).insert(j * step + offset, ":").toString().toLowerCase();
offset++;
}
String simplifiedMacAddressOfClonedVM = macAddress;
final String hostId = System.getProperty(VirtualBoxConstants.VIRTUALBOX_HOST_ID);
IMachine hostMachine = manager.getVBox().findMachine(hostId);
if (isOSX(hostMachine)) {
if (simplifiedMacAddressOfClonedVM.contains("00"))
simplifiedMacAddressOfClonedVM = new StringBuffer(simplifiedMacAddressOfClonedVM).delete(simplifiedMacAddressOfClonedVM.indexOf("00"), simplifiedMacAddressOfClonedVM.indexOf("00") + 1).toString();
if (simplifiedMacAddressOfClonedVM.contains("0"))
if (simplifiedMacAddressOfClonedVM.indexOf("0") + 1 != ':' && simplifiedMacAddressOfClonedVM.indexOf("0") - 1 != ':')
simplifiedMacAddressOfClonedVM = new StringBuffer(simplifiedMacAddressOfClonedVM).delete(simplifiedMacAddressOfClonedVM.indexOf("0"), simplifiedMacAddressOfClonedVM.indexOf("0") + 1).toString();
}
ExecResponse execResponse = runScriptOnNode(hostId, "for i in {1..254} ; do ping -c 1 -t 1 192.168.2.$i & done", runAsRoot(false).wrapInInitScript(false));
System.out.println(execResponse);
String arpLine = runScriptOnNode(hostId, "arp -an | grep " + simplifiedMacAddressOfClonedVM, runAsRoot(false).wrapInInitScript(false)).getOutput();
String ipAddress = arpLine.substring(arpLine.indexOf("(") + 1, arpLine.indexOf(")"));
System.out.println("IP address " + ipAddress);
return ipAddress;
}
private ExecResponse runScriptOnNode(String nodeId, String command, RunScriptOptions options) {
return computeService.runScriptOnNode(nodeId, command, options);
}
protected boolean isOSX(IMachine machine) {
String osTypeId = machine.getOSTypeId();
IGuestOSType guestOSType = manager.getVBox().getGuestOSType(osTypeId);
String familyDescription = guestOSType.getFamilyDescription();
return true;
}
}

View File

@ -19,36 +19,24 @@
package org.jclouds.virtualbox.functions;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Named;
import org.eclipse.jetty.server.Server;
import org.jclouds.collect.FindResourceInSet;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Processor;
import com.google.common.base.Function;
import org.jclouds.compute.domain.*;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationBuilder;
import org.jclouds.domain.LocationScope;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.logging.Logger;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.INetworkAdapter;
import org.virtualbox_4_1.MachineState;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import javax.annotation.Resource;
import javax.inject.Named;
import java.util.HashSet;
import java.util.Set;
import static org.jclouds.virtualbox.config.VirtualBoxComputeServiceContextModule.machineToNodeState;
public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata> {
@ -87,43 +75,21 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
nodeMetadataBuilder.hostname(vm.getName());
nodeMetadataBuilder.loginPort(18083);
Map<MachineState, NodeState> nodeStateMap = new HashMap<MachineState, NodeState>();
nodeStateMap.put(MachineState.Running, NodeState.RUNNING);
nodeStateMap.put(MachineState.PoweredOff, NodeState.SUSPENDED);
nodeStateMap.put(MachineState.DeletingSnapshot, NodeState.PENDING);
nodeStateMap.put(MachineState.DeletingSnapshotOnline, NodeState.PENDING);
nodeStateMap.put(MachineState.DeletingSnapshotPaused, NodeState.PENDING);
nodeStateMap.put(MachineState.FaultTolerantSyncing, NodeState.PENDING);
nodeStateMap.put(MachineState.LiveSnapshotting, NodeState.PENDING);
nodeStateMap.put(MachineState.SettingUp, NodeState.PENDING);
nodeStateMap.put(MachineState.Starting, NodeState.PENDING);
nodeStateMap.put(MachineState.Stopping, NodeState.PENDING);
nodeStateMap.put(MachineState.Restoring, NodeState.PENDING);
// TODO What to map these states to?
nodeStateMap.put(MachineState.FirstOnline, NodeState.PENDING);
nodeStateMap.put(MachineState.FirstTransient, NodeState.PENDING);
nodeStateMap.put(MachineState.LastOnline, NodeState.PENDING);
nodeStateMap.put(MachineState.LastTransient, NodeState.PENDING);
nodeStateMap.put(MachineState.Teleported, NodeState.PENDING);
nodeStateMap.put(MachineState.TeleportingIn, NodeState.PENDING);
nodeStateMap.put(MachineState.TeleportingPausedVM, NodeState.PENDING);
nodeStateMap.put(MachineState.Aborted, NodeState.ERROR);
nodeStateMap.put(MachineState.Stuck, NodeState.ERROR);
nodeStateMap.put(MachineState.Null, NodeState.UNRECOGNIZED);
MachineState vmState = vm.getState();
NodeState nodeState = nodeStateMap.get(vmState);
if(nodeState == null)
NodeState nodeState = machineToNodeState.get(vmState);
if (nodeState == null)
nodeState = NodeState.UNRECOGNIZED;
nodeMetadataBuilder.state(nodeState);
logger.debug("Setting virtualbox node to: " + nodeState + " from machine state: " + vmState);
INetworkAdapter networkAdapter = vm.getNetworkAdapter(0l);
if (networkAdapter != null) {
String bridgedInterface = networkAdapter.getBridgedInterface();
System.out.println("Interface: " + bridgedInterface);
}
// nodeMetadataBuilder.imageId("");
// nodeMetadataBuilder.group("");

View File

@ -0,0 +1,88 @@
/*
* *
* * 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.admin;
import com.google.common.base.Function;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.logging.Logger;
import org.jclouds.virtualbox.config.VirtualBoxConstants;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import java.io.*;
import java.net.URI;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.io.ByteStreams.copy;
import static com.google.common.io.Closeables.closeQuietly;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_WORKINGDIR;
/**
* @author Mattias Holmqvist
*/
public class FileDownloadFromURI implements Function<URI, File> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final ComputeServiceContext context;
private final String workingDir;
private final String isoFile;
@Inject
public FileDownloadFromURI(final ComputeServiceContext context,
@Named(VIRTUALBOX_WORKINGDIR) final String workingDir,
@Named(VirtualBoxConstants.VIRTUALBOX_ISOFILE) final String isoFile) {
this.context = context;
this.workingDir = workingDir;
this.isoFile = isoFile;
}
@Override
public File apply(@Nullable URI input) {
final File file = new File(workingDir, isoFile);
if (!file.exists()) {
final InputStream inputStream = context.utils().http().get(input);
checkNotNull(inputStream, "%s not found", input);
try {
copy(inputStream, new FileOutputStream(file));
return file;
} catch (FileNotFoundException e) {
logger.error(e, "File %s could not be found", file);
} catch (IOException e) {
logger.error(e, "Error when downloading file %s", input);
} finally {
closeQuietly(inputStream);
}
return null;
} else {
logger.debug("File %s already exists. Skipping download", file);
return file;
}
}
}

View File

@ -30,12 +30,11 @@ import org.jclouds.compute.StandaloneComputeServiceContextSpec;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.jclouds.virtualbox.VirtualBox;
import org.jclouds.virtualbox.VirtualBoxContextBuilder;
import org.jclouds.virtualbox.domain.VMSpec;
import org.jclouds.virtualbox.domain.Host;
import org.jclouds.virtualbox.domain.Image;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.VirtualBoxManager;
import java.util.Properties;
@ -75,8 +74,8 @@ public class VirtualBoxComputeServiceLiveTest extends BaseComputeServiceLiveTest
ComputeServiceContext context = null;
try {
context = new ComputeServiceContextFactory()
.createContext(new StandaloneComputeServiceContextSpec<VirtualBox, IMachine, VMSpec, Image, Host>(
"virtualbox", endpoint, apiversion, "", identity, credential, VirtualBox.class,
.createContext(new StandaloneComputeServiceContextSpec<VirtualBoxManager, IMachine, IMachine, IMachine, Host>(
"virtualbox", endpoint, apiversion, "", identity, credential, VirtualBoxManager.class,
VirtualBoxContextBuilder.class, ImmutableSet.<Module>of()));
context.getComputeService().listNodes();

View File

@ -177,8 +177,10 @@ public class KickstartTest2 {
context = TestUtils.computeServiceForLocalhost();
socketTester = new RetryablePredicate<IPSocket>(
new InetSocketAddressConnect(), 130, 10, TimeUnit.SECONDS);
setupCredentials();
setupConfigurationProperties();
downloadFileUnlessPresent(distroIsoUrl, workingDir, distroIsoName);
downloadFileUnlessPresent(gaIsoUrl, workingDir, gaIsoName);
@ -189,7 +191,7 @@ public class KickstartTest2 {
manager.connect(endpoint.toASCIIString(), identity, credential);
// Create machine
IMachine newVM = manager.getVBox().createMachine(settingsFile, vmName, osTypeId, vmId, forceOverwrite);
IMachine newVM = manager.getVBox().createMachine(settingsFile, vmName, osTypeId, "host", forceOverwrite);
manager.getVBox().registerMachine(newVM);
// Change RAM
@ -301,13 +303,11 @@ public class KickstartTest2 {
// Configure guest additions
// TODO generalize
if (isUbuntu(guestId)) {
runScriptOnNode(guestId, "m-a prepare -i", wrapInInitScript(true));
runScriptOnNode(guestId, "mount -o loop /dev/dvd /media/cdrom");
runScriptOnNode(guestId, "sh /media/cdrom/VBoxLinuxAdditions.run");
runScriptOnNode(guestId, "rm /etc/udev/rules.d/70-persistent-net.rules");
runScriptOnNode(guestId, "mkdir /etc/udev/rules.d/70-persistent-net.rules");
runScriptOnNode(guestId, "rm -rf /dev/.udev/");
runScriptOnNode(guestId, "rm /lib/udev/rules.d/75-persistent-net-generator.rules");
runScriptOnNode(guestId, "rm /etc/udev/rules.d/70-persistent-net.rules");
runScriptOnNode(guestId, "mkdir /etc/udev/rules.d/70-persistent-net.rules");
runScriptOnNode(guestId, "rm -rf /dev/.udev/");
runScriptOnNode(guestId, "rm /lib/udev/rules.d/75-persistent-net-generator.rules");
runScriptOnNode(guestId, "echo 0 | tee /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts");
}
logMachineStatus(machine);
@ -336,6 +336,7 @@ public class KickstartTest2 {
logMachineStatus(machine);
logger().debug("Changing to bridged networking...");
session = manager.getSessionObject();
IMachine adminNode = manager.getVBox().findMachine(vmName);
adminNode.lockMachine(session, LockType.Write);

View File

@ -31,16 +31,37 @@ import org.jclouds.compute.domain.OsFamily;
import org.jclouds.encryption.bouncycastle.config.BouncyCastleCryptoModule;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.jclouds.virtualbox.compute.LoadMachineFromVirtualBox;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
import org.jclouds.virtualbox.config.VirtualBoxConstants;
public class TestUtils {
public static ComputeServiceContext computeServiceForLocalhost() throws IOException {
String hostId = System.getProperty(VirtualBoxConstants.VIRTUALBOX_HOST_ID);
Node host = Node.builder().id(hostId)
.name(System.getProperty(VirtualBoxConstants.VIRTUALBOX_HOST_ID))
.hostname(System.getProperty(VirtualBoxConstants.VIRTUALBOX_HOSTNAME))
.osFamily(OsFamily.LINUX.toString())
.osDescription(System.getProperty("os.name"))
.osVersion(System.getProperty("os.version"))
.group("ssh")
.username(System.getProperty("user.name"))
.credentialUrl(privateKeyFile())
.build();
final Map<String, Node> nodeMap = ImmutableMap.<String, Node>builder().put(hostId, host).build();
return new ComputeServiceContextFactory().createContext("byon", "foo", "bar", ImmutableSet.<Module>of(
new SshjSshClientModule(), new SLF4JLoggingModule(), new BouncyCastleCryptoModule(), new CacheNodeStoreModule(nodeMap)));
}
public static ComputeServiceContext computeServiceForLocalhostAndGuest() throws IOException {
Node host = Node.builder().id("host")
.name("host installing virtualbox")
.hostname("localhost")
@ -68,7 +89,7 @@ public class TestUtils {
return new ComputeServiceContextFactory().createContext("byon", "foo", "bar", ImmutableSet.<Module>of(
new SshjSshClientModule(), new SLF4JLoggingModule(), new BouncyCastleCryptoModule(), new CacheNodeStoreModule(nodeMap)));
}
private static URI privateKeyFile() {
try {
return new URI("file://" + System.getProperty("user.home") + "/.ssh/id_rsa");
@ -77,4 +98,9 @@ public class TestUtils {
}
return null;
}
public static ComputeServiceContext computeServiceForVirtualBox(Cache<String, Node> cache) {
return new ComputeServiceContextFactory().createContext("byon", "foo", "bar", ImmutableSet.<Module>of(
new SshjSshClientModule(), new SLF4JLoggingModule(), new BouncyCastleCryptoModule(), new CacheNodeStoreModule(cache)));
}
}

View File

@ -22,12 +22,16 @@
package org.jclouds.virtualbox.experiment;
import com.google.common.base.Predicate;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Injector;
import com.google.inject.Module;
import org.jclouds.byon.Node;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.domain.Credentials;
import org.jclouds.logging.Logger;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
@ -37,17 +41,25 @@ import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.ssh.SshClient;
import org.jclouds.sshj.config.SshjSshClientModule;
import org.jclouds.virtualbox.compute.LoadMachineFromVirtualBox;
import org.jclouds.virtualbox.functions.IMachineToIpAddress;
import org.jclouds.virtualbox.functions.IMachineToNodeMetadata;
import org.virtualbox_4_1.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.compute.options.RunScriptOptions.Builder.wrapInInitScript;
import static org.jclouds.virtualbox.experiment.TestUtils.computeServiceForLocalhost;
import static org.jclouds.virtualbox.experiment.TestUtils.computeServiceForVirtualBox;
import static org.testng.Assert.assertEquals;
public class VirtualBoxLiveTest2 {
@ -58,6 +70,8 @@ public class VirtualBoxLiveTest2 {
protected String credential;
protected URI endpoint;
protected String vmName;
private String hostId = "host";
private String guestId = "guest";
VirtualBoxManager manager = VirtualBoxManager.createInstance("");
@ -78,13 +92,15 @@ public class VirtualBoxLiveTest2 {
protected int numberOfVirtualMachine;
protected String originalDisk;
private String clonedDisk;
private ComputeServiceContext context;
private ComputeServiceContext virtualBoxComputeService;
private String adminNodeName;
private Injector injector;
private Cache<String, Node> cache;
private ComputeServiceContext localhostComputeService;
protected Logger logger() {
return context.utils().loggerFactory().getLogger("jclouds.compute");
return virtualBoxComputeService.utils().loggerFactory().getLogger("jclouds.compute");
}
protected void setupCredentials() {
@ -122,7 +138,7 @@ public class VirtualBoxLiveTest2 {
numberOfVirtualMachine = Integer.parseInt(checkNotNull(System.getProperty("test." + provider
+ ".numberOfVirtualMachine", "3")));
injector = new RestContextFactory().createContextBuilder(provider,
ImmutableSet.<Module> of(new Log4JLoggingModule(), new SshjSshClientModule())).buildInjector();
ImmutableSet.<Module>of(new Log4JLoggingModule(), new SshjSshClientModule())).buildInjector();
sshFactory = injector.getInstance(SshClient.Factory.class);
}
@ -139,7 +155,11 @@ public class VirtualBoxLiveTest2 {
}
private void runAll() throws IOException, InterruptedException {
context = TestUtils.computeServiceForLocalhost();
localhostComputeService = computeServiceForLocalhost();
IMachineToIpAddress iMachineToIpAddress = new IMachineToIpAddress(manager, localhostComputeService.getComputeService());
LoadMachineFromVirtualBox cacheLoader = new LoadMachineFromVirtualBox(manager, iMachineToIpAddress);
cache = CacheBuilder.newBuilder().build(cacheLoader);
virtualBoxComputeService = computeServiceForVirtualBox(cache);
socketTester = new RetryablePredicate<IPSocket>(
new InetSocketAddressConnect(), 130, 10, TimeUnit.SECONDS);
setupCredentials();
@ -147,32 +167,29 @@ public class VirtualBoxLiveTest2 {
manager.connect(endpoint.toASCIIString(), identity, credential);
for (int i = 1; i < numberOfVirtualMachine + 1; i++) {
createAndLaunchVirtualMachine(i);
createAndLaunchVirtualMachine(1);
String instanceName = vmName + "_1";
IMachine machine = manager.getVBox().findMachine(instanceName);
logMachineStatus(machine);
try {
ISession machineSession = manager.openMachineSession(machine);
IProgress progress = machineSession.getConsole().powerDown();
progress.waitForCompletion(-1);
machineSession.unlockMachine();
while (!machine.getSessionState().equals(SessionState.Unlocked)) {
try {
logger().debug("Waiting for unlocking session - session state: " + machine.getSessionState());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
logMachineStatus(machine);
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 1; i < numberOfVirtualMachine + 1; i++) {
String instanceName = vmName + "_" + i;
IMachine machine = manager.getVBox().findMachine(instanceName);
logMachineStatus(machine);
try {
ISession machineSession = manager.openMachineSession(machine);
IProgress progress = machineSession.getConsole().powerDown();
progress.waitForCompletion(-1);
machineSession.unlockMachine();
while (!machine.getSessionState().equals(SessionState.Unlocked)) {
try {
logger().debug("Waiting for unlocking session - session state: " + machine.getSessionState());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
logMachineStatus(machine);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@ -184,30 +201,87 @@ public class VirtualBoxLiveTest2 {
List<CloneOptions> options = new ArrayList<CloneOptions>();
options.add(CloneOptions.Link);
IProgress progress = adminNode.getCurrentSnapshot().getMachine().cloneTo(clonedVM, CloneMode.MachineState, options);
if (progress.getCompleted())
logger().debug("clone done");
manager.getVBox().registerMachine(clonedVM);
ISession session = manager.getSessionObject();
clonedVM.lockMachine(session, LockType.Write);
IMachine mutable = session.getMachine();
// network
String hostInterface = null;
String command = "vboxmanage list bridgedifs";
try {
Process child = Runtime.getRuntime().exec(command);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(child.getInputStream()));
String line = "";
boolean found = false;
while ((line = bufferedReader.readLine()) != null && !found) {
System.out.println("line: " + line);
if (line.split(":")[0].contains("Name")) {
hostInterface = line.substring(line.indexOf(":") + 1);
}
if (line.split(":")[0].contains("Status") && line.split(":")[1].contains("Up")) {
System.out.println("bridge: " + hostInterface.trim());
found = true;
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mutable.getNetworkAdapter(new Long(0)).setAttachmentType(NetworkAttachmentType.Bridged);
mutable.getNetworkAdapter(new Long(0)).setAdapterType(NetworkAdapterType.Am79C973);
mutable.getNetworkAdapter(new Long(0)).setMACAddress("0800279DA478");
mutable.getNetworkAdapter(new Long(0)).setBridgedInterface(hostInterface.trim());
mutable.getNetworkAdapter(new Long(0)).setEnabled(true);
mutable.saveSettings();
session.unlockMachine();
System.out.println("\nLaunching VM named " + clonedVM.getName() + " ...");
launchVMProcess(clonedVM, manager.getSessionObject());
String ipAddress = null;
while (ipAddress == null || ipAddress.equals("")) {
try {
ipAddress = clonedVM.getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
clonedVM = manager.getVBox().findMachine(instanceName);
try {
boolean gotIp = false;
while (!gotIp) {
Node node = cache.get(instanceName);
if (node.getHostname() != null) {
gotIp = true;
}
else {
cache.invalidate(node);
Thread.sleep(1000);
System.out.println("waiting for IP: got IP");
}
}
} catch (ExecutionException e) {
}
logger().debug(ipAddress + " is the IP address of " + clonedVM.getName());
// TODO: This does not work yet.
// IPSocket socket = new IPSocket(ipAddress, 22);
// checkSSH(socket);
logger().debug("Trying echo...");
runScriptOnNode(instanceName, "echo ciao");
}
protected ExecResponse runScriptOnNode(String nodeId, String command) {
return runScriptOnNode(nodeId, command, wrapInInitScript(false));
}
protected ExecResponse runScriptOnNode(String nodeId, String command,
RunScriptOptions options) {
ExecResponse toReturn = virtualBoxComputeService.getComputeService().runScriptOnNode(nodeId, command, options);
assert toReturn.getExitCode() == 0 : toReturn;
return toReturn;
}
private void checkSSH(IPSocket socket) {
socketTester.apply(socket);
SshClient client = sshFactory.create(socket, new Credentials(osUsername, osPassword));

View File

@ -209,7 +209,7 @@ public class VirtualboxAdministrationKickstartLiveTest {
@BeforeGroups(groups = "live")
protected void setupClient() throws Exception {
context = TestUtils.computeServiceForLocalhost();
context = TestUtils.computeServiceForLocalhostAndGuest();
socketTester = new RetryablePredicate<IPSocket>(
new InetSocketAddressConnect(), 130, 10, TimeUnit.SECONDS);
setupCredentials();

View File

@ -168,7 +168,7 @@ public class VirtualboxLiveTest {
@BeforeGroups(groups = "live")
protected void setupClient() throws Exception {
context = TestUtils.computeServiceForLocalhost();
context = TestUtils.computeServiceForLocalhostAndGuest();
socketTester = new RetryablePredicate<IPSocket>(
new InetSocketAddressConnect(), 130, 10, TimeUnit.SECONDS);
setupCredentials();

View File

@ -19,14 +19,37 @@
package org.jclouds.virtualbox.functions;
import com.google.common.collect.ImmutableSet;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.domain.Credentials;
import org.jclouds.virtualbox.VirtualBox;
import org.jclouds.virtualbox.config.VirtualBoxComputeServiceContextModule;
import org.testng.annotations.Test;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.MachineState;
import org.virtualbox_4_1.VirtualBoxManager;
import java.util.Map;
import java.util.Set;
//@Test(groups = "live")
public class IMachineToNodeMetadataTest {
@Test
public void testCreate() throws Exception {
Credentials creds = new Credentials("admin", "123456");
VirtualBoxManager manager = VirtualBoxManager.createInstance("");
Map<MachineState, NodeState> machineToNodeState = VirtualBoxComputeServiceContextModule.machineToNodeState;
Set<Image> images = ImmutableSet.of();
Set<org.jclouds.compute.domain.Hardware> hardwares = ImmutableSet.of();
VirtualBox virtualBox = new VirtualBox();
IMachineToNodeMetadata parser = new IMachineToNodeMetadata();
IMachineToHardware hwParser = new IMachineToHardware(virtualBox);
// hwParser.apply()
}
}