Issue 412: added computeservice support to elasticstack

This commit is contained in:
Adrian Cole 2010-12-19 23:52:57 +01:00
parent 337ea7d4aa
commit 90ee548e8d
21 changed files with 1020 additions and 86 deletions

View File

@ -97,6 +97,22 @@ deltacloud.contextbuilder=org.jclouds.deltacloud.DeltacloudContextBuilder
elasticstack.propertiesbuilder=org.jclouds.elasticstack.ElasticStackPropertiesBuilder
elasticstack.contextbuilder=org.jclouds.elasticstack.ElasticStackContextBuilder
elasticstack.apiversion=1.0
elastichosts-lon-p.propertiesbuilder=org.jclouds.elasticstack.ElasticStackPropertiesBuilder
elastichosts-lon-p.contextbuilder=org.jclouds.elasticstack.ElasticStackContextBuilder
elastichosts-lon-p.apiversion=1.0
elastichosts-lon-p.endpoint=https://api.lon-p.elastichosts.com
elastichosts-lon-b.propertiesbuilder=org.jclouds.elasticstack.ElasticStackPropertiesBuilder
elastichosts-lon-b.contextbuilder=org.jclouds.elasticstack.ElasticStackContextBuilder
elastichosts-lon-b.apiversion=1.0
elastichosts-lon-b.endpoint=https://api.lon-b.elastichosts.com
elastichosts-sat-p.propertiesbuilder=org.jclouds.elasticstack.ElasticStackPropertiesBuilder
elastichosts-sat-p.contextbuilder=org.jclouds.elasticstack.ElasticStackContextBuilder
elastichosts-sat-p.apiversion=1.0
elastichosts-sat-p.endpoint=https://api.sat-p.elastichosts.com
cloudsigma.propertiesbuilder=org.jclouds.cloudsigma.CloudSigmaPropertiesBuilder
cloudsigma.contextbuilder=org.jclouds.cloudsigma.CloudSigmaContextBuilder

View File

@ -47,7 +47,6 @@ import com.google.common.base.Objects;
*
* @author Adrian Cole
*/
public class ParseAuthenticationResponseFromHeaders implements Function<HttpResponse, AuthenticationResponse>,
InvocationContext {

View File

@ -61,7 +61,7 @@
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<artifactId>jclouds-compute</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
@ -77,6 +77,13 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-compute</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>

View File

@ -22,8 +22,9 @@ package org.jclouds.elasticstack;
import java.util.List;
import java.util.Properties;
import org.jclouds.compute.ComputeServiceContextBuilder;
import org.jclouds.elasticstack.compute.config.ElasticStackComputeServiceContextModule;
import org.jclouds.elasticstack.config.ElasticStackRestClientModule;
import org.jclouds.rest.RestContextBuilder;
import com.google.inject.Module;
@ -32,11 +33,15 @@ import com.google.inject.Module;
* @author Adrian Cole
*/
public class ElasticStackContextBuilder extends
RestContextBuilder<ElasticStackClient, ElasticStackAsyncClient> {
ComputeServiceContextBuilder<ElasticStackClient, ElasticStackAsyncClient> {
public ElasticStackContextBuilder(Properties props) {
super(ElasticStackClient.class, ElasticStackAsyncClient.class, props);
}
@Override
protected void addContextModule(List<Module> modules) {
modules.add(new ElasticStackComputeServiceContextModule());
}
protected void addClientModule(List<Module> modules) {
modules.add(new ElasticStackRestClientModule());

View File

@ -19,7 +19,9 @@
package org.jclouds.elasticstack;
import static com.google.common.base.Preconditions.checkArgument;
import static org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.elasticstack.reference.ElasticStackConstants.PROPERTY_VNC_PASSWORD;
import java.util.Properties;
@ -35,9 +37,18 @@ public class ElasticStackPropertiesBuilder extends PropertiesBuilder {
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_API_VERSION, "1.0");
properties.setProperty(PROPERTY_API_VERSION, "IL9vs34d");
return properties;
}
@Override
public Properties build() {
Properties props = super.build();
checkArgument(props.getProperty(PROPERTY_VNC_PASSWORD).length() <= 8,
"vnc passwords should be less that 8 characters!");
return props;
}
public ElasticStackPropertiesBuilder(Properties properties) {
super(properties);
}

View File

@ -0,0 +1,213 @@
package org.jclouds.elasticstack.compute;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.notNull;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static org.jclouds.elasticstack.util.Servers.small;
import java.net.URI;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageBuilder;
import org.jclouds.compute.domain.OperatingSystemBuilder;
import org.jclouds.compute.domain.Processor;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.Volume;
import org.jclouds.compute.domain.internal.VolumeImpl;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import org.jclouds.domain.internal.LocationImpl;
import org.jclouds.elasticstack.ElasticStackClient;
import org.jclouds.elasticstack.domain.Device;
import org.jclouds.elasticstack.domain.Drive;
import org.jclouds.elasticstack.domain.DriveInfo;
import org.jclouds.elasticstack.domain.ImageConversionType;
import org.jclouds.elasticstack.domain.Server;
import org.jclouds.elasticstack.domain.ServerInfo;
import org.jclouds.elasticstack.domain.WellKnownImage;
import org.jclouds.elasticstack.reference.ElasticStackConstants;
import org.jclouds.logging.Logger;
import org.jclouds.rest.annotations.Provider;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
/**
* defines the connection between the {@link ElasticStackClient} implementation and the jclouds
* {@link ComputeService}
*
*/
@Singleton
public class ElasticStackComputeServiceAdapter implements ComputeServiceAdapter<ServerInfo, Hardware, Image, Location> {
private final ElasticStackClient client;
private final Predicate<DriveInfo> driveNotClaimed;
private final Supplier<Location> locationSupplier;
private final List<WellKnownImage> preinstalledImages;
private final String providerName;
private final URI providerURI;
private final String defaultVncPassword;
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
@Inject
public ElasticStackComputeServiceAdapter(ElasticStackClient client, Predicate<DriveInfo> driveNotClaimed,
Supplier<Location> locationSupplier, @Provider String providerName, @Provider URI providerURI,
List<WellKnownImage> preinstalledImages,
@Named(ElasticStackConstants.PROPERTY_VNC_PASSWORD) String defaultVncPassword) {
this.client = checkNotNull(client, "client");
this.driveNotClaimed = checkNotNull(driveNotClaimed, "driveNotClaimed");
this.locationSupplier = checkNotNull(locationSupplier, "locationSupplier");
this.providerName = checkNotNull(providerName, "providerName");
this.providerURI = checkNotNull(providerURI, "providerURI");
this.preinstalledImages = checkNotNull(preinstalledImages, "preinstalledImages");
this.defaultVncPassword = checkNotNull(defaultVncPassword, "defaultVncPassword");
}
@Override
public ServerInfo runNodeWithTagAndNameAndStoreCredentials(String tag, String name, Template template,
Map<String, Credentials> credentialStore) {
long bootSize = (long) (template.getHardware().getVolumes().get(0).getSize() * 1024 * 1024 * 1024l);
logger.debug(">> creating boot drive bytes(%d)", bootSize);
DriveInfo drive = client.createDrive(new Drive.Builder().name(template.getImage().getName()).size(bootSize)
.build());
logger.debug("<< drive(%s)", drive.getUuid());
logger.debug(">> imaging boot drive source(%s)", template.getImage().getId());
client.imageDrive(template.getImage().getId(), drive.getUuid(), ImageConversionType.GUNZIP);
boolean success = driveNotClaimed.apply(drive);
logger.debug("<< imaged (%s)", success);
if (!success) {
client.destroyDrive(drive.getUuid());
throw new IllegalStateException("could not image drive in time!");
}
Server toCreate = small(name, drive.getUuid(), defaultVncPassword).mem(template.getHardware().getRam())
.cpu((int) (template.getHardware().getProcessors().get(0).getSpeed())).build();
ServerInfo from = client.createAndStartServer(toCreate);
// store the credentials so that later functions can use them
credentialStore.put(from.getUuid() + "", new Credentials("toor", from.getVnc().getPassword()));
return from;
}
@Override
public Iterable<Hardware> listHardwareProfiles() {
Builder<Hardware> hardware = ImmutableSet.<Hardware> builder();
for (double cpu : new double[] { 1000, 5000, 10000, 20000 })
for (int ram : new int[] { 512, 1024, 2048, 4096, 8192 }) {
final float size = (float) cpu / 1000;
String id = String.format("cpu=%f,ram=%s,disk=%f", cpu, ram, size);
hardware.add(new HardwareBuilder().supportsImage(new Predicate<Image>() {
@Override
public boolean apply(Image input) {
String toParse = input.getUserMetadata().get("size");
return (toParse != null && new Float(toParse) <= size);
}
}).ids(id).ram(ram).processors(ImmutableList.of(new Processor(1, cpu)))
.volumes(ImmutableList.<Volume> of(new VolumeImpl(size, true, true))).build());
}
return hardware.build();
}
/**
* look up the current standard images and do not error out, if they are not found.
*/
@Override
public Iterable<Image> listImages() {
return filter(transform(preinstalledImages, new Function<WellKnownImage, Image>() {
@Override
public Image apply(WellKnownImage input) {
DriveInfo drive = null;
try {
drive = client.getDriveInfo(input.getUuid());
} catch (Exception e) {
logger.warn(e, "could not find image: %s", input);
}
if (drive == null) {
logger.warn("could not find image: %s", input);
return null;
}
return new ImageBuilder()
.ids(drive.getUuid())
.userMetadata(
ImmutableMap.<String, String> builder().putAll(drive.getUserMetadata())
.put("size", input.getSize() + "").build())
.defaultCredentials(new Credentials("toor", null))
.location(locationSupplier.get())
.name(input.getDescription())
.description(drive.getName())
.operatingSystem(
new OperatingSystemBuilder().family(input.getOsFamily()).version(input.getOsVersion())
.name(input.getDescription()).description(drive.getName()).is64Bit(true).build())
.version("").build();
}
}), notNull());
}
@SuppressWarnings("unchecked")
@Override
public Iterable<ServerInfo> listNodes() {
return (Iterable<ServerInfo>) client.listServerInfo();
}
@Override
public Iterable<Location> listLocations() {
return ImmutableSet.<Location> of(new LocationImpl(LocationScope.PROVIDER, providerName, providerURI
.toASCIIString(), null));
}
@Override
public ServerInfo getNode(String id) {
return client.getServerInfo(id);
}
@Override
public void destroyNode(String id) {
ServerInfo server = getNode(id);
if (server != null) {
client.destroyServer(id);
for (Device dev : server.getDevices().values())
client.destroyDrive(dev.getDriveUuid());
}
}
@Override
public void rebootNode(String id) {
client.resetServer(id);
}
@Override
public void resumeNode(String id) {
client.startServer(id);
}
@Override
public void suspendNode(String id) {
client.stopServer(id);
}
}

View File

@ -0,0 +1,145 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.elasticstack.compute.config;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
import org.jclouds.compute.config.JCloudsNativeComputeServiceAdapterContextModule.IdentityFunction;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Volume;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.suppliers.DefaultLocationSupplier;
import org.jclouds.domain.Location;
import org.jclouds.elasticstack.CommonElasticStackClient;
import org.jclouds.elasticstack.ElasticStackAsyncClient;
import org.jclouds.elasticstack.ElasticStackClient;
import org.jclouds.elasticstack.compute.ElasticStackComputeServiceAdapter;
import org.jclouds.elasticstack.compute.functions.ServerInfoToNodeMetadata;
import org.jclouds.elasticstack.compute.functions.ServerInfoToNodeMetadata.DeviceToVolume;
import org.jclouds.elasticstack.compute.functions.ServerInfoToNodeMetadata.FindImageForId;
import org.jclouds.elasticstack.compute.functions.ServerInfoToNodeMetadata.GetImageIdFromServer;
import org.jclouds.elasticstack.domain.Device;
import org.jclouds.elasticstack.domain.DriveInfo;
import org.jclouds.elasticstack.domain.Server;
import org.jclouds.elasticstack.domain.ServerInfo;
import org.jclouds.elasticstack.domain.WellKnownImage;
import org.jclouds.elasticstack.predicates.DriveClaimed;
import org.jclouds.json.Json;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.util.Utils;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.google.common.collect.MapMaker;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
/**
*
* @author Adrian Cole
*/
public class ElasticStackComputeServiceContextModule
extends
ComputeServiceAdapterContextModule<ElasticStackClient, ElasticStackAsyncClient, ServerInfo, Hardware, Image, Location> {
public ElasticStackComputeServiceContextModule() {
super(ElasticStackClient.class, ElasticStackAsyncClient.class);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
protected void configure() {
super.configure();
bind(new TypeLiteral<ComputeServiceAdapter<ServerInfo, Hardware, Image, Location>>() {
}).to(ElasticStackComputeServiceAdapter.class);
bind(IdentityFunction.class).toInstance(IdentityFunction.INSTANCE);
bind(new TypeLiteral<Supplier<Location>>() {
}).to(DefaultLocationSupplier.class);
bind(new TypeLiteral<Function<ServerInfo, NodeMetadata>>() {
}).to(ServerInfoToNodeMetadata.class);
bind(new TypeLiteral<Function<Image, Image>>() {
}).to((Class) IdentityFunction.class);
bind(new TypeLiteral<Function<Hardware, Hardware>>() {
}).to((Class) IdentityFunction.class);
bind(new TypeLiteral<Function<Location, Location>>() {
}).to((Class) IdentityFunction.class);
bind(new TypeLiteral<Function<Device, Volume>>() {
}).to(DeviceToVolume.class);
bind(new TypeLiteral<Function<Server, String>>() {
}).to(GetImageIdFromServer.class);
bind(new TypeLiteral<Function<String, Image>>() {
}).to(FindImageForId.class);
}
@Provides
@Singleton
protected Map<String, DriveInfo> cache(GetDrive getDrive) {
return new MapMaker().expiration(30, TimeUnit.SECONDS).makeComputingMap(getDrive);
}
@Singleton
public static class GetDrive implements Function<String, DriveInfo> {
private final ElasticStackClient client;
@Inject
public GetDrive(ElasticStackClient client) {
this.client = client;
}
@Override
public DriveInfo apply(String input) {
return client.getDriveInfo(input);
}
}
@Singleton
@Provides
protected List<WellKnownImage> provideImages(Json json) throws IOException {
return json.fromJson(Utils.toStringAndClose(getClass().getResourceAsStream("/preinstalled_images.json")),
new TypeLiteral<List<WellKnownImage>>() {
}.getType());
}
@Provides
@Singleton
protected CommonElasticStackClient convert(ElasticStackClient in) {
return in;
}
@Provides
@Singleton
protected Predicate<DriveInfo> supplyDriveUnclaimed(DriveClaimed driveClaimed,
ComputeServiceConstants.Timeouts timeouts) {
return new RetryablePredicate<DriveInfo>(Predicates.not(driveClaimed), timeouts.nodeRunning, 1000,
TimeUnit.MILLISECONDS);
}
}

View File

@ -0,0 +1,174 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.elasticstack.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.compute.util.ComputeServiceUtils.parseTagFromName;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.collect.FindResourceInSet;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.compute.domain.Image;
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 org.jclouds.compute.domain.Volume;
import org.jclouds.compute.domain.VolumeBuilder;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.elasticstack.domain.Device;
import org.jclouds.elasticstack.domain.DriveInfo;
import org.jclouds.elasticstack.domain.Server;
import org.jclouds.elasticstack.domain.ServerInfo;
import org.jclouds.elasticstack.domain.ServerStatus;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
*/
@Singleton
public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetadata> {
public static final Map<ServerStatus, NodeState> serverStatusToNodeState = ImmutableMap
.<ServerStatus, NodeState> builder().put(ServerStatus.ACTIVE, NodeState.RUNNING)//
.put(ServerStatus.STOPPED, NodeState.SUSPENDED)//
.put(ServerStatus.PAUSED, NodeState.SUSPENDED)//
.put(ServerStatus.DUMPED, NodeState.PENDING)//
.put(ServerStatus.DEAD, NodeState.TERMINATED)//
.put(ServerStatus.UNRECOGNIZED, NodeState.UNRECOGNIZED)//
.build();
private final Function<Server, String> getImageIdFromServer;
private final Function<String, Image> findImageForId;
private final Map<String, Credentials> credentialStore;
private final Supplier<Location> locationSupplier;
private final Function<Device, Volume> deviceToVolume;
@Inject
ServerInfoToNodeMetadata(Map<String, Credentials> credentialStore, Function<Server, String> getImageIdFromServer,
Function<String, Image> findImageForId, Function<Device, Volume> deviceToVolume,
Supplier<Location> locationSupplier) {
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
this.locationSupplier = checkNotNull(locationSupplier, "locationSupplier");
this.deviceToVolume = checkNotNull(deviceToVolume, "deviceToVolume");
this.findImageForId = checkNotNull(findImageForId, "findImageForId");
this.getImageIdFromServer = checkNotNull(getImageIdFromServer, "getImageIdFromServer");
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public NodeMetadata apply(ServerInfo from) {
NodeMetadataBuilder builder = new NodeMetadataBuilder();
builder.ids(from.getUuid());
builder.name(from.getName());
builder.location(locationSupplier.get());
builder.tag(parseTagFromName(from.getName()));
String imageId = getImageIdFromServer.apply(from);
if (imageId != null) {
Image image = findImageForId.apply(imageId);
if (image != null) {
builder.operatingSystem(image.getOperatingSystem());
}
}
builder.hardware(new HardwareBuilder().ids(from.getUuid())
.processors(ImmutableList.of(new Processor(1, from.getCpu()))).ram(from.getMem())
.volumes((List) ImmutableList.of(Iterables.transform(from.getDevices().values(), deviceToVolume))).build());
builder.state(serverStatusToNodeState.get(from.getStatus()));
builder.publicAddresses(ImmutableSet.<String> of(from.getVnc().getIp()));
builder.privateAddresses(ImmutableSet.<String> of());
builder.credentials(credentialStore.get(from.getUuid()));
return builder.build();
}
@Singleton
public static final class DeviceToVolume implements Function<Device, Volume> {
private final Map<String, DriveInfo> cache;
@Inject
public DeviceToVolume(Map<String, DriveInfo> cache) {
this.cache = checkNotNull(cache, "cache");
}
@Override
public Volume apply(Device input) {
VolumeBuilder builder = new VolumeBuilder();
builder.id(input.getId());
DriveInfo drive = cache.get(input.getDriveUuid());
if (drive != null) {
builder.size(drive.getSize() / 1024 / 1024f);
}
return new VolumeBuilder().durable(true).type(Volume.Type.NAS).build();
}
}
@Singleton
public static class GetImageIdFromServer implements Function<Server, String> {
private final Map<String, DriveInfo> cache;
@Inject
public GetImageIdFromServer(Map<String, DriveInfo> cache) {
this.cache = cache;
}
@Override
public String apply(Server from) {
String imageId = null;
String bootDeviceId = Iterables.get(from.getBootDeviceIds(), 0);
Device bootDevice = from.getDevices().get(bootDeviceId);
if (bootDevice != null) {
try {
imageId = cache.get(bootDevice.getDriveUuid()).getUuid();
} catch (NullPointerException e) {
}
}
return imageId;
}
}
@Singleton
public static class FindImageForId extends FindResourceInSet<String, Image> {
@Inject
public FindImageForId(@Memoized Supplier<Set<? extends Image>> images) {
super(images);
}
@Override
public boolean matches(String from, Image input) {
return input.getProviderId().equals(from);
}
}
}

View File

@ -144,7 +144,7 @@ public class Server extends Item {
protected final int mem;
protected final boolean persistent;
@Nullable
protected final Map<String, ? extends Device> devices;
protected final Map<String, Device> devices;
protected final Set<String> bootDeviceIds;
protected final List<NIC> nics;
protected final VNC vnc;
@ -203,7 +203,7 @@ public class Server extends Item {
*
* @return devices present, mapped by id
*/
public Map<String, ? extends Device> getDevices() {
public Map<String, Device> getDevices() {
return devices;
}

View File

@ -0,0 +1,82 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.elasticstack.domain;
import org.jclouds.compute.domain.OsFamily;
import com.google.common.base.Objects;
/**
*
* @author Adrian Cole
*/
public class WellKnownImage {
private String uuid;
private String description;
private OsFamily osFamily;
private String osVersion;
private int size;
// intended only for serialization
WellKnownImage() {
}
// performance isn't a concern on a infrequent object like this, so using shortcuts;
public String getUuid() {
return uuid;
}
public String getDescription() {
return description;
}
public OsFamily getOsFamily() {
return osFamily;
}
public String getOsVersion() {
return osVersion;
}
public int getSize() {
return size;
}
@Override
public int hashCode() {
return Objects.hashCode(uuid, description, osFamily, osVersion, size);
}
@Override
public boolean equals(Object that) {
if (that == null)
return false;
return Objects.equal(this.toString(), that.toString());
}
@Override
public String toString() {
return Objects.toStringHelper(this).add("uuid", uuid).add("description", description).add("osFamily", osFamily)
.add("osVersion", osVersion).add("size", size).toString();
}
}

View File

@ -61,7 +61,8 @@ public class ElasticStackErrorHandler implements HttpErrorHandler {
response.getStatusLine());
switch (response.getStatusCode()) {
case 400:
if (message != null && message.indexOf("could not be found") != -1)
if ((command.getRequest().getEndpoint().getPath().endsWith("/info"))
|| (message != null && message.indexOf("could not be found") != -1))
exception = new ResourceNotFoundException(message, exception);
else
exception = new IllegalArgumentException(message, exception);

View File

@ -0,0 +1,34 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.elasticstack.reference;
/**
* Common constants used in ElasticStack provider
*
* @author Adrian Cole
*/
public class ElasticStackConstants {
/**
* default VNC password used on new machines
*/
public static final String PROPERTY_VNC_PASSWORD = "jclouds.elasticstack.vnc-password";
}

View File

@ -0,0 +1,72 @@
[
{
"uuid": "38df0986-4d85-4b76-b502-3878ffc80161",
"description": "CentOS Linux 5.5",
"osFamily": "CENTOS",
"osVersion": "5.5",
"size": "3"
},
{
"uuid": "980cf63c-f21e-4382-997b-6541d5809629",
"description": "Debian Linux 5.0",
"osFamily": "DEBIAN",
"osVersion": "5.0",
"size": "1"
},
{
"uuid": "aee5589a-88c3-43ef-bb0a-9cab6e64192d",
"description": "Ubuntu Linux 10.04",
"osFamily": "UBUNTU",
"osVersion": "10.04",
"size": "1"
},
{
"uuid": "bf1d943e-2a55-46bb-a8c7-6099e44a3dde",
"description": "Ubuntu Linux 8.10: Base system with X",
"osFamily": "UBUNTU",
"osVersion": "8.10",
"size": "3"
},
{
"uuid": "757586d5-f1e9-4d9c-b215-5a391c9a24bf",
"description": "Ubuntu Linux 9.04: Base system with X",
"osFamily": "UBUNTU",
"osVersion": "9.04",
"size": "3"
},
{
"uuid": "b9d0eb72-d273-43f1-98e3-0d4b87d372c0",
"description": "Windows Web Server 2008",
"osFamily": "WINDOWS",
"osVersion": "2008",
"size": "13"
},
{
"uuid": "b405b598-4ae4-4ba8-8a2b-a9487d693f34",
"description": "Windows Web Server 2008 R2",
"osFamily": "WINDOWS",
"osVersion": "2008 R2",
"size": "13"
},
{
"uuid": "9397d327-3bf6-46a2-abf6-69553dbb6927",
"description": "Windows Web Server 2008 R2 + SQL Server",
"osFamily": "WINDOWS",
"osVersion": "2008 R2",
"size": "13"
},
{
"uuid": "10a88d1c-6575-46e3-8d2c-7744065ea530",
"description": "Windows Server 2008 Standard R2",
"osFamily": "WINDOWS",
"osVersion": "2008 R2",
"size": "13"
},
{
"uuid": "662c5b3f-9828-4aa2-a866-7cfa53798cdf",
"description": "Windows Server 2008 Standard R2 + SQL Server",
"osFamily": "WINDOWS",
"osVersion": "2008 R2",
"size": "13"
}
]

View File

@ -30,6 +30,7 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import org.jclouds.Constants;
import org.jclouds.compute.ComputeServiceContextFactory;
import org.jclouds.domain.Credentials;
import org.jclouds.elasticstack.domain.ClaimType;
import org.jclouds.elasticstack.domain.CreateDriveRequest;
@ -48,7 +49,6 @@ import org.jclouds.net.IPSocket;
import org.jclouds.predicates.InetSocketAddressConnect;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
@ -84,7 +84,7 @@ public abstract class CommonElasticStackClientLiveTest<S extends CommonElasticSt
protected String credential;
protected String endpoint;
protected String apiversion;
protected RetryablePredicate<DriveInfo> driveNotClaimed;
protected Predicate<DriveInfo> driveNotClaimed;
protected void setupCredentials() {
identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider + ".identity");
@ -111,8 +111,8 @@ public abstract class CommonElasticStackClientLiveTest<S extends CommonElasticSt
public void setupClient() {
setupCredentials();
Properties overrides = setupProperties();
context = new RestContextFactory().createContext(provider, ImmutableSet.<Module> of(new Log4JLoggingModule()),
overrides);
context = new ComputeServiceContextFactory().createContext(provider,
ImmutableSet.<Module> of(new Log4JLoggingModule()), overrides).getProviderSpecificContext();
client = context.getApi();
driveNotClaimed = new RetryablePredicate<DriveInfo>(Predicates.not(new DriveClaimed(client)), maxDriveImageTime,
@ -319,6 +319,9 @@ public abstract class CommonElasticStackClientLiveTest<S extends CommonElasticSt
ssh.connect();
ExecResponse hello = ssh.exec("echo hello");
assertEquals(hello.getOutput().trim(), "hello");
System.err.println(ssh.exec("df -k").getOutput());
System.err.println(ssh.exec("mount").getOutput());
System.err.println(ssh.exec("uname -a").getOutput());
} finally {
if (ssh != null)
ssh.disconnect();

View File

@ -70,14 +70,13 @@ public class ElasticStackClientLiveTest extends
@Override
protected Credentials getSshCredentials(Server server) {
// according to paul from elastichosts, this account should be present
return new Credentials("toor", server.getVnc().getPassword());
}
@Override
protected void prepareDrive() {
System.err.println("before prepare" + client.getDriveInfo(drive.getUuid()));
client.imageDrive("e6111e4c-67af-4438-b1bc-189747d5a8e5", drive.getUuid(), ImageConversionType.GUNZIP);
client.imageDrive("38df0986-4d85-4b76-b502-3878ffc80161", drive.getUuid(), ImageConversionType.GUNZIP);
assert driveNotClaimed.apply(drive) : client.getDriveInfo(drive.getUuid());
System.err.println("after prepare" + client.getDriveInfo(drive.getUuid()));
}

View File

@ -19,6 +19,7 @@
package org.jclouds.elasticstack;
import org.jclouds.compute.util.ComputeServiceUtils;
import org.jclouds.util.Utils;
import org.testng.annotations.Test;
@ -36,12 +37,18 @@ public class ProvidersInPropertiesTest {
public void testSupportedProviders() {
Iterable<String> providers = Utils.getSupportedProviders();
assert Iterables.contains(providers, "elasticstack") : providers;
assert Iterables.contains(providers, "elastichosts-lon-p") : providers;
assert Iterables.contains(providers, "elastichosts-lon-b") : providers;
assert Iterables.contains(providers, "elastichosts-sat-p") : providers;
}
@Test
public void testSupportedComputeServiceProviders() {
Iterable<String> providers = ComputeServiceUtils.getSupportedProviders();
assert Iterables.contains(providers, "elasticstack") : providers;
assert Iterables.contains(providers, "elastichosts-lon-p") : providers;
assert Iterables.contains(providers, "elastichosts-lon-b") : providers;
assert Iterables.contains(providers, "elastichosts-sat-p") : providers;
}
//
// @Test
// public void testSupportedComputeServiceProviders() {
// Iterable<String> providers = ComputeServiceUtils.getSupportedProviders();
// assert Iterables.contains(providers, "cloudsigma") : providers;
// }
}

View File

@ -0,0 +1,39 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.elasticstack.compute;
import org.jclouds.compute.BaseComputeServiceLiveTest;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = "live")
public class ElasticStackComputeServiceLiveTest extends BaseComputeServiceLiveTest {
public ElasticStackComputeServiceLiveTest() {
provider = "elasticstack";
}
@Override
protected JschSshClientModule getSshModule() {
return new JschSshClientModule();
}
}

View File

@ -0,0 +1,56 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.elasticstack.compute;
import org.jclouds.compute.BaseTemplateBuilderLiveTest;
import org.jclouds.compute.OsFamilyVersion64Bit;
import org.jclouds.compute.domain.OsFamily;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
/**
*
* @author Adrian Cole
*/
@Test(groups = "live")
public class ElasticStackTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
public ElasticStackTemplateBuilderLiveTest() {
provider = "elasticstack";
}
@Override
protected Predicate<OsFamilyVersion64Bit> defineUnsupportedOperatingSystems() {
return new Predicate<OsFamilyVersion64Bit>() {
@Override
public boolean apply(OsFamilyVersion64Bit input) {
return ((input.family == OsFamily.RHEL) || //
(input.family == OsFamily.CENTOS && !(input.version.equals("5.5") && input.is64Bit)) || //
(input.family == OsFamily.UBUNTU && !(input.version.equals("10.04") && input.is64Bit)) || //
(input.family == OsFamily.WINDOWS && !((input.version.equals("2008") || input.version.equals("2008 R2")) && input.is64Bit)) //
);
}
};
}
}

View File

@ -52,9 +52,20 @@ public class ElasticStackErrorHandlerTest {
IllegalArgumentException.class);
}
@Test
public void test400MakesResourceNotFoundExceptionOnInfo() {
assertCodeMakes("GET", URI.create("https://elasticstack.com/foo/info"), 400, "", "",
ResourceNotFoundException.class);
}
@Test
public void test400MakesResourceNotFoundExceptionOnMessageNotFound() {
assertCodeMakes("GET", URI.create("https://elasticstack.com/foo"), 400, "", "errors:system Drive 8f9b42b1-26de-49ad-a3fd-d4fa06524339 could not be found. Please re-validate your entry.",
assertCodeMakes(
"GET",
URI.create("https://elasticstack.com/foo"),
400,
"",
"errors:system Drive 8f9b42b1-26de-49ad-a3fd-d4fa06524339 could not be found. Please re-validate your entry.",
ResourceNotFoundException.class);
}

View File

@ -2,28 +2,27 @@
<!--
Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
Copyright (C) 2010 Cloud Conscious, LLC.
<info@cloudconscious.com>
====================================================================
Licensed 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.
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.
====================================================================
-->
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!--
For more configuration infromation and examples see the Apache Log4j
website: http://logging.apache.org/log4j/
For more configuration infromation and examples see the Apache
Log4j website: http://logging.apache.org/log4j/
-->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
debug="false">
@ -39,13 +38,13 @@
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message${symbol_escape}n -->
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category] (Thread:NDC) Message${symbol_escape}n
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
%m%n"/>
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
@ -61,17 +60,69 @@
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message${symbol_escape}n -->
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category] (Thread:NDC) Message${symbol_escape}n
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
%m%n"/>
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="COMPUTEFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-compute.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="SSHFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-ssh.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message\n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<appender name="ASYNCCOMPUTE" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="COMPUTEFILE" />
</appender>
<appender name="ASYNCSSH" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="SSHFILE" />
</appender>
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
@ -94,11 +145,20 @@
<appender-ref ref="ASYNCWIRE" />
</category>
<category name="jclouds.ssh">
<priority value="DEBUG" />
<appender-ref ref="ASYNCSSH" />
</category>
<category name="jclouds.wire">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category>
<category name="jclouds.compute">
<priority value="TRACE" />
<appender-ref ref="ASYNCCOMPUTE" />
</category>
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->