Issue 204: add template description, Issue 162: update to correct image and location details

This commit is contained in:
Adrian Cole 2010-03-11 11:29:46 -08:00
parent b36d68417c
commit 79c54e9f45
7 changed files with 550 additions and 486 deletions

View File

@ -40,6 +40,11 @@ public interface Image extends ComputeMetadata {
*/
String getVersion();
/**
* Description of the image.
*/
String getDescription();
/**
* Operating System
*/

View File

@ -98,15 +98,20 @@ public interface TemplateBuilder {
*/
TemplateBuilder osDescriptionMatches(String osDescriptionRegex);
/**
* Configure this template to have an image name that matches the regular expression
*/
TemplateBuilder imageNameMatches(String imageNameRegex);
/**
* Configure this template to have an image version that matches the regular expression
*/
TemplateBuilder imageVersionMatches(String imageVersionRegex);
/**
* Configure this template to have a description that matches the regular expression
* Configure this template to have an image description that matches the regular expression
*/
TemplateBuilder imageDescriptionMatches(String descriptionRegex);
TemplateBuilder imageDescriptionMatches(String imageDescriptionRegex);
/**
* Configure this template to require the minimum cores below

View File

@ -44,6 +44,7 @@ public class ImageImpl extends ComputeMetadataImpl implements Image {
private static final long serialVersionUID = 7856744554191025307L;
private final String version;
private final String description;
private final OsFamily osFamily;
private final String osDescription;
private final Architecture architecture;
@ -54,6 +55,7 @@ public class ImageImpl extends ComputeMetadataImpl implements Image {
super(ComputeType.IMAGE, id, name, locationId, uri, userMetadata);
this.version = checkNotNull(version, "version");
this.osFamily = osFamily;
this.description = checkNotNull(description, "description");
this.osDescription = checkNotNull(osDescription, "osDescription");
this.architecture = checkNotNull(architecture, "architecture");
}
@ -66,6 +68,14 @@ public class ImageImpl extends ComputeMetadataImpl implements Image {
return version;
}
/**
* {@inheritDoc}
*/
@Override
public String getDescription() {
return description;
}
/**
* {@inheritDoc}
*/
@ -93,8 +103,9 @@ public class ImageImpl extends ComputeMetadataImpl implements Image {
@Override
public String toString() {
return "[id=" + getId() + ", name=" + getName() + ", locationId=" + getLocationId()
+ ", architecture=" + architecture + ", osDescription=" + osDescription
+ ", osFamily=" + osFamily + ", version=" + version + "]";
+ ", architecture=" + architecture + ", description=" + description
+ ", osDescription=" + osDescription + ", osFamily=" + osFamily + ", version="
+ version + "]";
}
@Override
@ -102,6 +113,7 @@ public class ImageImpl extends ComputeMetadataImpl implements Image {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((architecture == null) ? 0 : architecture.hashCode());
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((osDescription == null) ? 0 : osDescription.hashCode());
result = prime * result + ((osFamily == null) ? 0 : osFamily.hashCode());
result = prime * result + ((version == null) ? 0 : version.hashCode());
@ -122,6 +134,11 @@ public class ImageImpl extends ComputeMetadataImpl implements Image {
return false;
} else if (!architecture.equals(other.architecture))
return false;
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (osDescription == null) {
if (other.osDescription != null)
return false;

View File

@ -53,6 +53,7 @@ public class TemplateBuilderImpl implements TemplateBuilder {
private String osDescription;
private String imageVersion;
private String imageName;
private String imageDescription;
private double minCores;
private int minRam;
@ -127,8 +128,11 @@ public class TemplateBuilderImpl implements TemplateBuilder {
if (input.getOsDescription() == null)
returnVal = false;
else
returnVal = input.getOsDescription().contains(osDescription) ||
input.getOsDescription().matches(osDescription); /*note: matches() expects a regex!*/
returnVal = input.getOsDescription().contains(osDescription)
|| input.getOsDescription().matches(osDescription); /*
* note: matches()
* expects a regex!
*/
}
return returnVal;
}
@ -159,7 +163,19 @@ public class TemplateBuilderImpl implements TemplateBuilder {
return returnVal;
}
};
private final Predicate<Image> imageDescriptionPredicate = new Predicate<Image>() {
@Override
public boolean apply(Image input) {
boolean returnVal = true;
if (imageDescription != null) {
if (input.getName() == null)
returnVal = false;
else
returnVal = input.getName().matches(imageDescription);
}
return returnVal;
}
};
private final Predicate<Size> sizeIdPredicate = new Predicate<Size>() {
@Override
public boolean apply(Size input) {
@ -177,7 +193,7 @@ public class TemplateBuilderImpl implements TemplateBuilder {
private final Predicate<Image> imagePredicate = Predicates.and(idPredicate, locationPredicate,
osPredicate, imageArchPredicate, osDescriptionPredicate, imageVersionPredicate,
imageNamePredicate);
imageNamePredicate, imageDescriptionPredicate);
private final Predicate<Size> sizeArchPredicate = new Predicate<Size>() {
@Override
@ -221,9 +237,10 @@ public class TemplateBuilderImpl implements TemplateBuilder {
return ComparisonChain.start().compare(left.getName(), right.getName(),
Ordering.<String> natural().nullsLast()).compare(left.getVersion(),
right.getVersion(), Ordering.<String> natural().nullsLast()).compare(
left.getOsDescription(), right.getOsDescription(),
Ordering.<String> natural().nullsLast()).compare(left.getArchitecture(),
right.getArchitecture()).result();
left.getDescription(), right.getDescription(),
Ordering.<String> natural().nullsLast()).compare(left.getOsDescription(),
right.getOsDescription(), Ordering.<String> natural().nullsLast()).compare(
left.getArchitecture(), right.getArchitecture()).result();
}
};
@ -258,6 +275,10 @@ public class TemplateBuilderImpl implements TemplateBuilder {
this.locationId = image.getLocationId();
if (image.getOsFamily() != null)
this.os = image.getOsFamily();
if (image.getName() != null)
this.imageName = image.getName();
if (image.getDescription() != null)
this.imageDescription = image.getDescription();
if (image.getOsDescription() != null)
this.osDescription = image.getOsDescription();
if (image.getVersion() != null)
@ -365,12 +386,21 @@ public class TemplateBuilderImpl implements TemplateBuilder {
return this;
}
/**
* {@inheritDoc}
*/
@Override
public TemplateBuilder imageNameMatches(String nameRegex) {
this.imageName = nameRegex;
return this;
}
/**
* {@inheritDoc}
*/
@Override
public TemplateBuilder imageDescriptionMatches(String descriptionRegex) {
this.imageName = descriptionRegex;
this.imageDescription = descriptionRegex;
return this;
}
@ -430,11 +460,11 @@ public class TemplateBuilderImpl implements TemplateBuilder {
@Override
public String toString() {
return "[arch=" + arch + ", biggest=" + biggest + ", fastest=" + fastest
+ ", imageDescription=" + imageName + ", imageId=" + imageId + ", imageVersion="
+ imageVersion + ", location=" + locationId + ", minCores=" + minCores + ", minRam="
+ minRam + ", os=" + os + ", osDescription=" + osDescription + ", sizeId=" + sizeId
+ "]";
return "[arch=" + arch + ", biggest=" + biggest + ", fastest=" + fastest + ", imageName="
+ imageName + ", imageDescription=" + imageDescription + ", imageId=" + imageId
+ ", imageVersion=" + imageVersion + ", location=" + locationId + ", minCores="
+ minCores + ", minRam=" + minRam + ", os=" + os + ", osDescription="
+ osDescription + ", sizeId=" + sizeId + "]";
}
}

View File

@ -18,39 +18,8 @@
*/
package org.jclouds.gogrid.config;
import com.google.common.base.*;
import com.google.common.collect.*;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.*;
import org.jclouds.compute.domain.internal.ImageImpl;
import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.compute.domain.internal.SizeImpl;
import org.jclouds.compute.internal.ComputeServiceContextImpl;
import org.jclouds.compute.predicates.RunScriptRunning;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.*;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import org.jclouds.domain.internal.LocationImpl;
import org.jclouds.gogrid.GoGridAsyncClient;
import org.jclouds.gogrid.GoGridClient;
import org.jclouds.gogrid.domain.*;
import org.jclouds.gogrid.options.GetIpListOptions;
import org.jclouds.gogrid.predicates.ServerLatestJobCompleted;
import org.jclouds.gogrid.util.GoGridUtils;
import org.jclouds.logging.Logger;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rest.RestContext;
import org.jclouds.ssh.SshClient;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.SecureRandom;
@ -59,397 +28,430 @@ import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;
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.ComputeServiceContext;
import org.jclouds.compute.domain.Architecture;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.internal.ImageImpl;
import org.jclouds.compute.domain.internal.NodeMetadataImpl;
import org.jclouds.compute.domain.internal.SizeImpl;
import org.jclouds.compute.internal.ComputeServiceContextImpl;
import org.jclouds.compute.predicates.RunScriptRunning;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.AddNodeWithTagStrategy;
import org.jclouds.compute.strategy.DestroyNodeStrategy;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.RebootNodeStrategy;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import org.jclouds.domain.internal.LocationImpl;
import org.jclouds.gogrid.GoGridAsyncClient;
import org.jclouds.gogrid.GoGridClient;
import org.jclouds.gogrid.domain.Ip;
import org.jclouds.gogrid.domain.IpType;
import org.jclouds.gogrid.domain.PowerCommand;
import org.jclouds.gogrid.domain.Server;
import org.jclouds.gogrid.domain.ServerImage;
import org.jclouds.gogrid.options.GetIpListOptions;
import org.jclouds.gogrid.predicates.ServerLatestJobCompleted;
import org.jclouds.gogrid.util.GoGridUtils;
import org.jclouds.logging.Logger;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rest.RestContext;
import org.jclouds.ssh.SshClient;
import com.google.common.base.CharMatcher;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
/**
* @author Oleksiy Yarmula
*/
public class GoGridComputeServiceContextModule extends GoGridContextModule {
@Override
protected void configure() {
super.configure();
bind(new TypeLiteral<Function<Server, NodeMetadata>>() {
}).to(ServerToNodeMetadata.class);
bind(AddNodeWithTagStrategy.class).to(GoGridAddNodeWithTagStrategy.class);
bind(ListNodesStrategy.class).to(GoGridListNodesStrategy.class);
bind(GetNodeMetadataStrategy.class).to(GoGridGetNodeMetadataStrategy.class);
bind(RebootNodeStrategy.class).to(GoGridRebootNodeStrategy.class);
bind(DestroyNodeStrategy.class).to(GoGridDestroyNodeStrategy.class);
}
@Override
protected void configure() {
super.configure();
bind(new TypeLiteral<Function<Server, NodeMetadata>>() {
}).to(ServerToNodeMetadata.class);
bind(AddNodeWithTagStrategy.class).to(GoGridAddNodeWithTagStrategy.class);
bind(ListNodesStrategy.class).to(GoGridListNodesStrategy.class);
bind(GetNodeMetadataStrategy.class).to(GoGridGetNodeMetadataStrategy.class);
bind(RebootNodeStrategy.class).to(GoGridRebootNodeStrategy.class);
bind(DestroyNodeStrategy.class).to(GoGridDestroyNodeStrategy.class);
}
@Provides
@Named("NAMING_CONVENTION")
@Singleton
String provideNamingConvention() {
return "%s-%d";
}
@Provides
@Named("NAMING_CONVENTION")
@Singleton
String provideNamingConvention() {
return "%s-%d";
}
@Singleton
public static class GoGridAddNodeWithTagStrategy implements AddNodeWithTagStrategy {
private final GoGridClient client;
private final Function<Size, String> sizeToRam;
private final Function<Server, NodeMetadata> serverToNodeMetadata;
private RetryablePredicate<Server> serverLatestJobCompleted;
private RetryablePredicate<Server> serverLatestJobCompletedShort;
@Singleton
public static class GoGridAddNodeWithTagStrategy implements AddNodeWithTagStrategy {
private final GoGridClient client;
private final Function<Size, String> sizeToRam;
private final Function<Server, NodeMetadata> serverToNodeMetadata;
private RetryablePredicate<Server> serverLatestJobCompleted;
private RetryablePredicate<Server> serverLatestJobCompletedShort;
@Inject
protected GoGridAddNodeWithTagStrategy(GoGridClient client,
Function<Server, NodeMetadata> serverToNodeMetadata,
Function<Size, String> sizeToRam) {
this.client = client;
this.serverToNodeMetadata = serverToNodeMetadata;
this.sizeToRam = sizeToRam;
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()),
800, 20, TimeUnit.SECONDS);
this.serverLatestJobCompletedShort = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()),
60, 20, TimeUnit.SECONDS);
}
@Inject
protected GoGridAddNodeWithTagStrategy(GoGridClient client,
Function<Server, NodeMetadata> serverToNodeMetadata, Function<Size, String> sizeToRam) {
this.client = client;
this.serverToNodeMetadata = serverToNodeMetadata;
this.sizeToRam = sizeToRam;
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()), 800, 20, TimeUnit.SECONDS);
this.serverLatestJobCompletedShort = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()), 60, 20, TimeUnit.SECONDS);
}
@Override
public NodeMetadata execute(String tag, String name, Template template) {
Server addedServer = null;
boolean notStarted = true;
int numOfRetries = 20;
// lock-free consumption of a shared resource: IP address pool
while(notStarted) { // TODO: replace with Predicate-based thread collision avoidance for simplicity
Set<Ip> availableIps =
client.getIpServices().getIpList(new GetIpListOptions().onlyUnassigned().onlyWithType(IpType.PUBLIC));
if(availableIps.size() == 0) throw new RuntimeException("No public IPs available on this account.");
int ipIndex = new SecureRandom().nextInt(availableIps.size());
Ip availableIp = Iterables.get(availableIps, ipIndex);
try {
addedServer = client.getServerServices().addServer(name, checkNotNull(template.getImage().getId()),
sizeToRam.apply(template.getSize()), availableIp.getIp());
notStarted = false;
} catch(Exception e) {
if(--numOfRetries == 0) Throwables.propagate(e);
notStarted = true;
}
}
serverLatestJobCompleted.apply(addedServer);
client.getServerServices().power(addedServer.getName(), PowerCommand.START);
serverLatestJobCompletedShort.apply(addedServer);
addedServer = Iterables.getOnlyElement(
client.getServerServices().getServersByName(addedServer.getName())
);
return serverToNodeMetadata.apply(addedServer);
}
}
@Singleton
public static class GoGridRebootNodeStrategy implements RebootNodeStrategy {
private final GoGridClient client;
private RetryablePredicate<Server> serverLatestJobCompleted;
private RetryablePredicate<Server> serverLatestJobCompletedShort;
@Inject
protected GoGridRebootNodeStrategy(GoGridClient client) {
this.client = client;
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()),
800, 20, TimeUnit.SECONDS);
this.serverLatestJobCompletedShort = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()),
60, 20, TimeUnit.SECONDS);
}
@Override
public boolean execute(ComputeMetadata node) {
Server server =
Iterables.getOnlyElement(client.getServerServices().getServersByName(node.getName()));
client.getServerServices().power(server.getName(), PowerCommand.RESTART);
serverLatestJobCompleted.apply(server);
client.getServerServices().power(server.getName(), PowerCommand.START);
return serverLatestJobCompletedShort.apply(server);
}
}
@Singleton
public static class GoGridListNodesStrategy implements ListNodesStrategy {
private final GoGridClient client;
private final Function<Server, NodeMetadata> serverToNodeMetadata;
@Inject
protected GoGridListNodesStrategy(GoGridClient client,
Function<Server, NodeMetadata> serverToNodeMetadata) {
this.client = client;
this.serverToNodeMetadata = serverToNodeMetadata;
}
@Override
public Iterable<? extends ComputeMetadata> execute() {
return Iterables.transform(client.getServerServices().getServerList(), serverToNodeMetadata);
}
}
@Singleton
public static class GoGridGetNodeMetadataStrategy implements GetNodeMetadataStrategy {
private final GoGridClient client;
private final Function<Server, NodeMetadata> serverToNodeMetadata;
@Inject
protected GoGridGetNodeMetadataStrategy(GoGridClient client,
Function<Server, NodeMetadata> serverToNodeMetadata) {
this.client = client;
this.serverToNodeMetadata = serverToNodeMetadata;
}
@Override
public NodeMetadata execute(ComputeMetadata node) {
Server server = Iterables.getOnlyElement(
client.getServerServices().getServersByName(node.getName())
);
return server == null ? null : serverToNodeMetadata.apply(server);
}
}
@Singleton
public static class GoGridDestroyNodeStrategy implements DestroyNodeStrategy {
private final GoGridClient client;
private RetryablePredicate<Server> serverLatestJobCompleted;
@Inject
protected GoGridDestroyNodeStrategy(GoGridClient client) {
this.client = client;
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()),
800, 20, TimeUnit.SECONDS);
}
@Override
public boolean execute(ComputeMetadata node) {
Server server = Iterables.getOnlyElement(
client.getServerServices().getServersByName(node.getName()));
client.getServerServices().deleteByName(server.getName());
return serverLatestJobCompleted.apply(server);
}
}
@Singleton
@Provides
Map<String, NodeState> provideServerToNodeState() {
return ImmutableMap.<String, NodeState> builder()
.put("On", NodeState.RUNNING)
.put("Starting", NodeState.PENDING)
.put("Off", NodeState.SUSPENDED)
.put("Saving", NodeState.PENDING)
.put("Restarting", NodeState.PENDING)
.put("Stopping", NodeState.PENDING)
.build();
}
@Singleton
@Provides
Function<String, InetAddress> provideStringIpToInetAddress() {
return new Function<String, InetAddress>() {
@Override
public InetAddress apply(String from) {
try {
return InetAddress.getByName(from);
} catch (UnknownHostException e) {
// TODO: log the failure.
return null;
}
}
};
}
/**
* Finds matches to required configurations.
* GoGrid's documentation only specifies how much RAM one can get with
* different instance types. The # of cores and disk sizes are purely
* empyrical and aren't guaranteed.
* However, these are the matches found:
* Ram: 512MB, CPU: 1 core, HDD: 28 GB
* Ram: 1GB, CPU: 1 core, HDD: 57 GB
* Ram: 2GB, CPU: 1 core, HDD: 113 GB
* Ram: 4GB, CPU: 3 cores, HDD: 233 GB
* Ram: 8GB, CPU: 6 cores, HDD: 462 GB
* @return matched size
*/
@Singleton
@Provides
Function<Size, String> provideSizeToRam() {
return new Function<Size, String>() {
@Override
public String apply(Size size) {
if(size.getRam() >= 8 * 1024 || size.getCores() >= 6 || size.getDisk() >= 450) return "8GB";
if(size.getRam() >= 4 * 1024 || size.getCores() >= 3 || size.getDisk() >= 230) return "4GB";
if(size.getRam() >= 2 * 1024 || size.getDisk() >= 110) return "2GB";
if(size.getRam() >= 1024 || size.getDisk() >= 55) return "1GB";
return "512MB"; /*smallest*/
}
};
}
@Singleton
private static class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
private final Map<String, NodeState> serverStateToNodeState;
private final Function<String, InetAddress> stringIpToInetAddress;
private final GoGridClient client;
@Inject
ServerToNodeMetadata(Map<String, NodeState> serverStateToNodeState,
Function<String, InetAddress> stringIpToInetAddress,
GoGridClient client) {
this.serverStateToNodeState = serverStateToNodeState;
this.stringIpToInetAddress = stringIpToInetAddress;
this.client = client;
}
@Override
public NodeMetadata apply(Server from) {
String locationId = "Unavailable";
String tag = CharMatcher.JAVA_LETTER.retainFrom(from.getName());
Credentials creds = client.getServerServices().getServerCredentialsList().get(from.getName());
Set<InetAddress> ipSet =
ImmutableSet.of(stringIpToInetAddress.apply(from.getIp().getIp()));
NodeState state = serverStateToNodeState.get(from.getState().getName());
return new NodeMetadataImpl(from.getId() + "", from.getName(), locationId, null,
ImmutableMap.<String, String> of(), tag, state,
ipSet,
ImmutableList.<InetAddress> of(), ImmutableMap.<String, String> of(), creds);
}
}
@Provides
@Singleton
ComputeServiceContext provideContext(ComputeService computeService,
RestContext<GoGridAsyncClient, GoGridClient> context) {
return new ComputeServiceContextImpl<GoGridAsyncClient, GoGridClient>(
computeService, context);
}
@Provides
@Singleton
@Named("NOT_RUNNING")
protected Predicate<SshClient> runScriptRunning(RunScriptRunning stateRunning) {
return new RetryablePredicate<SshClient>(Predicates.not(stateRunning), 600, 3,
TimeUnit.SECONDS);
}
@Provides
@Singleton
Location getDefaultLocation(Map<String, ? extends Location> locations) {
return locations.get("SANJOSE");
}
@Provides
@Singleton
Map<String, ? extends Location> getDefaultLocations(GoGridClient sync, LogHolder holder,
Function<ComputeMetadata, String> indexer) {
final Set<Location> locations = Sets.newHashSet();
holder.logger.debug(">> providing empty locations because gogrid doesnt have any");
locations.add(new LocationImpl(LocationScope.REGION, "SANJOSE", "GoGrid doesnt support locations so using " +
"a made up one to comply with API", "Santa Clara County", true));
holder.logger.debug("<< locations(%d)", locations.size());
return Maps.uniqueIndex(locations, new Function<Location, String>() {
@Override
public String apply(Location from) {
return from.getId();
}
});
}
@Provides
@Singleton
protected Function<ComputeMetadata, String> indexer() {
return new Function<ComputeMetadata, String>() {
@Override
public String apply(ComputeMetadata from) {
return from.getId();
}
};
}
@Provides
@Singleton
protected Map<String, ? extends Size> provideSizes(GoGridClient sync,
Map<String, ? extends Image> images, LogHolder holder,
Function<ComputeMetadata, String> indexer) throws InterruptedException,
TimeoutException, ExecutionException {
final Set<Size> sizes = Sets.newHashSet();
holder.logger.debug(">> providing sizes");
sizes.add(new SizeImpl("1", "1", null, null,
ImmutableMap.<String, String> of(), 1, 512, 28,
ImmutableSet.<Architecture> of(Architecture.X86_32,
Architecture.X86_64)));
sizes.add(new SizeImpl("2", "2", null, null,
ImmutableMap.<String, String> of(), 1, 1024, 57,
ImmutableSet.<Architecture> of(Architecture.X86_32,
Architecture.X86_64)));
sizes.add(new SizeImpl("3", "3", null, null,
ImmutableMap.<String, String> of(), 1, 2048, 113,
ImmutableSet.<Architecture> of(Architecture.X86_32,
Architecture.X86_64)));
sizes.add(new SizeImpl("4", "4", null, null,
ImmutableMap.<String, String> of(), 3, 4096, 233,
ImmutableSet.<Architecture> of(Architecture.X86_32,
Architecture.X86_64)));
sizes.add(new SizeImpl("5", "5", null, null,
ImmutableMap.<String, String> of(), 6, 8192, 462,
ImmutableSet.<Architecture> of(Architecture.X86_32,
Architecture.X86_64)));
holder.logger.debug("<< sizes(%d)", sizes.size());
return Maps.uniqueIndex(sizes, indexer);
}
private static class LogHolder {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
}
public static final Pattern GOGRID_OS_NAME_PATTERN = Pattern.compile("([a-zA-Z]*)(.*)");
public static final Pattern GOGRID_OS_VERSION_PATTERN = Pattern.compile("([a-zA-Z\\s]*)(\\d(\\.)*\\d+)");
@Provides
@Singleton
protected Map<String, ? extends Image> provideImages(final GoGridClient sync,
LogHolder holder, Function<ComputeMetadata, String> indexer)
throws InterruptedException, ExecutionException, TimeoutException {
final Set<Image> images = Sets.newHashSet();
holder.logger.debug(">> providing images");
Set<ServerImage> allImages = sync.getImageServices().getImageList();
for (ServerImage from : allImages) {
OsFamily os = null;
Architecture arch = (from.getOs().getName().indexOf("64") == -1 &&
from.getDescription().indexOf("64") == -1) ?
Architecture.X86_32 : Architecture.X86_64;
String osDescription;
String version = "";
osDescription = from.getOs().getName();
String matchedOs = GoGridUtils.parseStringByPatternAndGetNthMatchGroup(from.getOs().getName(),
GOGRID_OS_NAME_PATTERN, 1);
@Override
public NodeMetadata execute(String tag, String name, Template template) {
Server addedServer = null;
boolean notStarted = true;
int numOfRetries = 20;
// lock-free consumption of a shared resource: IP address pool
while (notStarted) { // TODO: replace with Predicate-based thread collision avoidance for
// simplicity
Set<Ip> availableIps = client.getIpServices().getIpList(
new GetIpListOptions().onlyUnassigned().onlyWithType(IpType.PUBLIC));
if (availableIps.size() == 0)
throw new RuntimeException("No public IPs available on this account.");
int ipIndex = new SecureRandom().nextInt(availableIps.size());
Ip availableIp = Iterables.get(availableIps, ipIndex);
try {
os = OsFamily.fromValue(matchedOs.toLowerCase());
} catch (IllegalArgumentException e) {
holder.logger.debug("<< didn't match os(%s)", matchedOs);
addedServer = client.getServerServices().addServer(name,
checkNotNull(template.getImage().getId()),
sizeToRam.apply(template.getSize()), availableIp.getIp());
notStarted = false;
} catch (Exception e) {
if (--numOfRetries == 0)
Throwables.propagate(e);
notStarted = true;
}
}
serverLatestJobCompleted.apply(addedServer);
version = GoGridUtils.parseStringByPatternAndGetNthMatchGroup(from.getOs().getName(),
GOGRID_OS_VERSION_PATTERN, 2);
client.getServerServices().power(addedServer.getName(), PowerCommand.START);
serverLatestJobCompletedShort.apply(addedServer);
images.add(new ImageImpl(from.getName(), from.getDescription(), null, null, ImmutableMap
.<String, String> of(), from.getDescription(), version, os, osDescription, arch));
}
holder.logger.debug("<< images(%d)", images.size());
return Maps.uniqueIndex(images, indexer);
}
addedServer = Iterables.getOnlyElement(client.getServerServices().getServersByName(
addedServer.getName()));
return serverToNodeMetadata.apply(addedServer);
}
}
@Singleton
public static class GoGridRebootNodeStrategy implements RebootNodeStrategy {
private final GoGridClient client;
private RetryablePredicate<Server> serverLatestJobCompleted;
private RetryablePredicate<Server> serverLatestJobCompletedShort;
@Inject
protected GoGridRebootNodeStrategy(GoGridClient client) {
this.client = client;
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()), 800, 20, TimeUnit.SECONDS);
this.serverLatestJobCompletedShort = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()), 60, 20, TimeUnit.SECONDS);
}
@Override
public boolean execute(ComputeMetadata node) {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersByName(
node.getName()));
client.getServerServices().power(server.getName(), PowerCommand.RESTART);
serverLatestJobCompleted.apply(server);
client.getServerServices().power(server.getName(), PowerCommand.START);
return serverLatestJobCompletedShort.apply(server);
}
}
@Singleton
public static class GoGridListNodesStrategy implements ListNodesStrategy {
private final GoGridClient client;
private final Function<Server, NodeMetadata> serverToNodeMetadata;
@Inject
protected GoGridListNodesStrategy(GoGridClient client,
Function<Server, NodeMetadata> serverToNodeMetadata) {
this.client = client;
this.serverToNodeMetadata = serverToNodeMetadata;
}
@Override
public Iterable<? extends ComputeMetadata> execute() {
return Iterables.transform(client.getServerServices().getServerList(),
serverToNodeMetadata);
}
}
@Singleton
public static class GoGridGetNodeMetadataStrategy implements GetNodeMetadataStrategy {
private final GoGridClient client;
private final Function<Server, NodeMetadata> serverToNodeMetadata;
@Inject
protected GoGridGetNodeMetadataStrategy(GoGridClient client,
Function<Server, NodeMetadata> serverToNodeMetadata) {
this.client = client;
this.serverToNodeMetadata = serverToNodeMetadata;
}
@Override
public NodeMetadata execute(ComputeMetadata node) {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersByName(
node.getName()));
return server == null ? null : serverToNodeMetadata.apply(server);
}
}
@Singleton
public static class GoGridDestroyNodeStrategy implements DestroyNodeStrategy {
private final GoGridClient client;
private RetryablePredicate<Server> serverLatestJobCompleted;
@Inject
protected GoGridDestroyNodeStrategy(GoGridClient client) {
this.client = client;
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()), 800, 20, TimeUnit.SECONDS);
}
@Override
public boolean execute(ComputeMetadata node) {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersByName(
node.getName()));
client.getServerServices().deleteByName(server.getName());
return serverLatestJobCompleted.apply(server);
}
}
@Singleton
@Provides
Map<String, NodeState> provideServerToNodeState() {
return ImmutableMap.<String, NodeState> builder().put("On", NodeState.RUNNING).put(
"Starting", NodeState.PENDING).put("Off", NodeState.SUSPENDED).put("Saving",
NodeState.PENDING).put("Restarting", NodeState.PENDING).put("Stopping",
NodeState.PENDING).build();
}
@Singleton
@Provides
Function<String, InetAddress> provideStringIpToInetAddress() {
return new Function<String, InetAddress>() {
@Override
public InetAddress apply(String from) {
try {
return InetAddress.getByName(from);
} catch (UnknownHostException e) {
// TODO: log the failure.
return null;
}
}
};
}
/**
* Finds matches to required configurations. GoGrid's documentation only specifies how much RAM
* one can get with different instance types. The # of cores and disk sizes are purely empyrical
* and aren't guaranteed. However, these are the matches found: Ram: 512MB, CPU: 1 core, HDD: 28
* GB Ram: 1GB, CPU: 1 core, HDD: 57 GB Ram: 2GB, CPU: 1 core, HDD: 113 GB Ram: 4GB, CPU: 3
* cores, HDD: 233 GB Ram: 8GB, CPU: 6 cores, HDD: 462 GB
*
* @return matched size
*/
@Singleton
@Provides
Function<Size, String> provideSizeToRam() {
return new Function<Size, String>() {
@Override
public String apply(Size size) {
if (size.getRam() >= 8 * 1024 || size.getCores() >= 6 || size.getDisk() >= 450)
return "8GB";
if (size.getRam() >= 4 * 1024 || size.getCores() >= 3 || size.getDisk() >= 230)
return "4GB";
if (size.getRam() >= 2 * 1024 || size.getDisk() >= 110)
return "2GB";
if (size.getRam() >= 1024 || size.getDisk() >= 55)
return "1GB";
return "512MB"; /* smallest */
}
};
}
@Singleton
private static class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
private final Map<String, NodeState> serverStateToNodeState;
private final Function<String, InetAddress> stringIpToInetAddress;
private final GoGridClient client;
@Inject
ServerToNodeMetadata(Map<String, NodeState> serverStateToNodeState,
Function<String, InetAddress> stringIpToInetAddress, GoGridClient client) {
this.serverStateToNodeState = serverStateToNodeState;
this.stringIpToInetAddress = stringIpToInetAddress;
this.client = client;
}
@Override
public NodeMetadata apply(Server from) {
String locationId = "Unavailable";
String tag = CharMatcher.JAVA_LETTER.retainFrom(from.getName());
Credentials creds = client.getServerServices().getServerCredentialsList().get(
from.getName());
Set<InetAddress> ipSet = ImmutableSet
.of(stringIpToInetAddress.apply(from.getIp().getIp()));
NodeState state = serverStateToNodeState.get(from.getState().getName());
return new NodeMetadataImpl(from.getId() + "", from.getName(), locationId, null,
ImmutableMap.<String, String> of(), tag, state, ipSet, ImmutableList
.<InetAddress> of(), ImmutableMap.<String, String> of(), creds);
}
}
@Provides
@Singleton
ComputeServiceContext provideContext(ComputeService computeService,
RestContext<GoGridAsyncClient, GoGridClient> context) {
return new ComputeServiceContextImpl<GoGridAsyncClient, GoGridClient>(computeService, context);
}
@Provides
@Singleton
@Named("NOT_RUNNING")
protected Predicate<SshClient> runScriptRunning(RunScriptRunning stateRunning) {
return new RetryablePredicate<SshClient>(Predicates.not(stateRunning), 600, 3,
TimeUnit.SECONDS);
}
@Provides
@Singleton
Location getDefaultLocation(Map<String, ? extends Location> locations) {
return locations.get("SANFRANCISCO");
}
@Provides
@Singleton
Map<String, ? extends Location> getDefaultLocations(GoGridClient sync, LogHolder holder,
Function<ComputeMetadata, String> indexer) {
final Set<Location> locations = Sets.newHashSet();
holder.logger.debug(">> providing locations");
locations.add(new LocationImpl(LocationScope.ZONE, "SANFRANCISCO", "San Francisco, CA", null,
true));
holder.logger.debug("<< locations(%d)", locations.size());
return Maps.uniqueIndex(locations, new Function<Location, String>() {
@Override
public String apply(Location from) {
return from.getId();
}
});
}
@Provides
@Singleton
protected Function<ComputeMetadata, String> indexer() {
return new Function<ComputeMetadata, String>() {
@Override
public String apply(ComputeMetadata from) {
return from.getId();
}
};
}
@Provides
@Singleton
protected Map<String, ? extends Size> provideSizes(GoGridClient sync,
Map<String, ? extends Image> images, LogHolder holder,
Function<ComputeMetadata, String> indexer) throws InterruptedException,
TimeoutException, ExecutionException {
final Set<Size> sizes = Sets.newHashSet();
holder.logger.debug(">> providing sizes");
sizes.add(new SizeImpl("1", "1", null, null, ImmutableMap.<String, String> of(), 1, 512, 28,
ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
sizes.add(new SizeImpl("2", "2", null, null, ImmutableMap.<String, String> of(), 1, 1024, 57,
ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
sizes.add(new SizeImpl("3", "3", null, null, ImmutableMap.<String, String> of(), 1, 2048,
113, ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
sizes.add(new SizeImpl("4", "4", null, null, ImmutableMap.<String, String> of(), 3, 4096,
233, ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
sizes.add(new SizeImpl("5", "5", null, null, ImmutableMap.<String, String> of(), 6, 8192,
462, ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
holder.logger.debug("<< sizes(%d)", sizes.size());
return Maps.uniqueIndex(sizes, indexer);
}
private static class LogHolder {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
}
public static final Pattern GOGRID_OS_NAME_PATTERN = Pattern.compile("([a-zA-Z]*)(.*)");
@Provides
@Singleton
protected Map<String, ? extends Image> provideImages(final GoGridClient sync, LogHolder holder,
Function<ComputeMetadata, String> indexer, Location location)
throws InterruptedException, ExecutionException, TimeoutException {
final Set<Image> images = Sets.newHashSet();
holder.logger.debug(">> providing images");
Set<ServerImage> allImages = sync.getImageServices().getImageList();
for (ServerImage from : allImages) {
OsFamily os = null;
Architecture arch = (from.getOs().getName().indexOf("64") == -1 && from.getDescription()
.indexOf("64") == -1) ? Architecture.X86_32 : Architecture.X86_64;
String osDescription;
String version = "";
osDescription = from.getOs().getName();
String matchedOs = GoGridUtils.parseStringByPatternAndGetNthMatchGroup(from.getOs()
.getName(), GOGRID_OS_NAME_PATTERN, 1);
try {
os = OsFamily.fromValue(matchedOs.toLowerCase());
} catch (IllegalArgumentException e) {
holder.logger.debug("<< didn't match os(%s)", matchedOs);
}
images.add(new ImageImpl(from.getId() + "", from.getFriendlyName(), location.getId(), null,
ImmutableMap.<String, String> of(), from.getDescription(), version, os,
osDescription, arch));
}
holder.logger.debug("<< images(%d)", images.size());
return Maps.uniqueIndex(images, indexer);
}
}

View File

@ -21,9 +21,9 @@ package org.jclouds.gogrid;
import static org.jclouds.compute.domain.OsFamily.CENTOS;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.Map;
import com.google.common.base.Predicate;
import org.jclouds.compute.BaseComputeServiceLiveTest;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContextFactory;
@ -34,82 +34,84 @@ import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.rest.RestContext;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import javax.annotation.Nullable;
/**
* @author Oleksiy Yarmula
*/
@Test(groups = "live", enabled = true, sequential = true, testName = "gogrid.GoGridComputeServiceLiveTest")
public class GoGridComputeServiceLiveTest extends BaseComputeServiceLiveTest {
@BeforeClass
@Override
public void setServiceDefaults() {
service = "gogrid";
}
@BeforeClass
@Override
public void setServiceDefaults() {
service = "gogrid";
}
@Override
public String buildScript() {
return
new StringBuilder()//
.append("echo nameserver 208.67.222.222 >> /etc/resolv.conf\n")//
.append("echo \"[jdkrepo]\" >> /etc/yum.repos.d/CentOS-Base.repo\n")
.append("echo \"name=jdkrepository\" >> /etc/yum.repos.d/CentOS-Base.repo\n")
.append("echo \"baseurl=http://ec2-us-east-mirror.rightscale.com/epel/5/i386/\" >> /etc/yum.repos.d/CentOS-Base.repo\n")
.append("echo \"enabled=1\" >> /etc/yum.repos.d/CentOS-Base.repo\n")
.append("yum -y install java-1.6.0-openjdk\n")
.append("echo \"export PATH=\\\"/usr/lib/jvm/jre-1.6.0-openjdk/bin/:\\$PATH\\\"\" >> /root/.bashrc\n")
.toString();
}
@Override
public String buildScript() {
return new StringBuilder()
//
.append("echo nameserver 208.67.222.222 >> /etc/resolv.conf\n")
//
.append("echo \"[jdkrepo]\" >> /etc/yum.repos.d/CentOS-Base.repo\n")
.append("echo \"name=jdkrepository\" >> /etc/yum.repos.d/CentOS-Base.repo\n")
.append(
"echo \"baseurl=http://ec2-us-east-mirror.rightscale.com/epel/5/i386/\" >> /etc/yum.repos.d/CentOS-Base.repo\n")
.append("echo \"enabled=1\" >> /etc/yum.repos.d/CentOS-Base.repo\n")
.append("yum -y install java-1.6.0-openjdk\n")
.append(
"echo \"export PATH=\\\"/usr/lib/jvm/jre-1.6.0-openjdk/bin/:\\$PATH\\\"\" >> /root/.bashrc\n")
.toString();
}
protected Template buildTemplate(TemplateBuilder templateBuilder) {
return templateBuilder.osFamily(CENTOS).imageId("centos5.3_32_base").smallest().build();
}
protected Template buildTemplate(TemplateBuilder templateBuilder) {
return templateBuilder.osFamily(CENTOS).imageDescriptionMatches(".*w/ None.*").smallest()
.build();
}
@Override
protected JschSshClientModule getSshModule() {
return new JschSshClientModule();
}
@Override
protected JschSshClientModule getSshModule() {
return new JschSshClientModule();
}
public void testAssignability() throws Exception {
@SuppressWarnings("unused")
RestContext<GoGridAsyncClient, GoGridClient> goGridContext = new ComputeServiceContextFactory()
.createContext(service, user, password).getProviderSpecificContext();
}
public void testAssignability() throws Exception {
@SuppressWarnings("unused")
RestContext<GoGridAsyncClient, GoGridClient> goGridContext = new ComputeServiceContextFactory()
.createContext(service, user, password).getProviderSpecificContext();
}
@Test(enabled = true)
public void endToEndComputeServiceTest() {
ComputeService service = context.getComputeService();
Template t = service.templateBuilder().minRam(1024).imageId(
"GSI-6890f8b6-c8fb-4ac1-bc33-2563eb4e29d2").build();
@Test(enabled = true)
public void endToEndComputeServiceTest() {
ComputeService service = context.getComputeService();
Template t = service.templateBuilder().minRam(1024).imageId("1532").build();
int originalSize = service.getNodes().size();
int originalSize = service.getNodes().size();
assertEquals(t.getImage().getId(), "GSI-6890f8b6-c8fb-4ac1-bc33-2563eb4e29d2");
service.runNodesWithTag(this.service, 1, t);
assertEquals(t.getImage().getId(), "1532");
service.runNodesWithTag(this.service, 1, t);
Map<String, ? extends ComputeMetadata> nodes = service.getNodes();
assertEquals(nodes.size(), originalSize + 1, "size should've been larger by 1");
Map<String, ? extends ComputeMetadata> nodes = service.getNodes();
assertEquals(nodes.size(), originalSize + 1, "size should've been larger by 1");
ComputeMetadata node = Iterables.find(nodes.values(), new Predicate<ComputeMetadata>() {
@Override public boolean apply(ComputeMetadata computeMetadata) {
return computeMetadata.getName().startsWith(GoGridComputeServiceLiveTest.this.service);
}
});
ComputeMetadata node = Iterables.find(nodes.values(), new Predicate<ComputeMetadata>() {
@Override
public boolean apply(ComputeMetadata computeMetadata) {
return computeMetadata.getName().startsWith(GoGridComputeServiceLiveTest.this.service);
}
});
NodeMetadata nodeMetadata = service.getNodeMetadata(node);
assertEquals(nodeMetadata.getPublicAddresses().size(), 1,
"There must be 1 public address for the node");
assertTrue(nodeMetadata.getName().startsWith(this.service));
service.rebootNode(nodeMetadata); // blocks until finished
NodeMetadata nodeMetadata = service.getNodeMetadata(node);
assertEquals(nodeMetadata.getPublicAddresses().size(), 1,
"There must be 1 public address for the node");
assertTrue(nodeMetadata.getName().startsWith(this.service));
service.rebootNode(nodeMetadata); // blocks until finished
assertEquals(service.getNodeMetadata(nodeMetadata).getState(), NodeState.RUNNING);
service.destroyNode(nodeMetadata);
}
assertEquals(service.getNodeMetadata(nodeMetadata).getState(), NodeState.RUNNING);
service.destroyNode(nodeMetadata);
}
}

View File

@ -149,9 +149,12 @@ public class ComputeTask extends Task {
private void listImages(ComputeService computeService) {
log("list images");
for (Image image : computeService.getImages().values()) {// TODO
log(String.format(" image location=%s, id=%s, version=%s, arch=%s, osfam=%s, desc=%s",
image.getLocationId(), image.getId(), image.getVersion(),
image.getArchitecture(), image.getOsFamily(), image.getOsDescription()));
log(String
.format(
" image location=%s, id=%s, name=%s, version=%s, arch=%s, osfam=%s, osdesc=%s, desc=%s",
image.getLocationId(), image.getId(), image.getName(), image
.getVersion(), image.getArchitecture(), image.getOsFamily(),
image.getOsDescription(), image.getDescription()));
}
}