mirror of https://github.com/apache/jclouds.git
Merge branch 'master' of https://github.com/jclouds/jclouds into 1.5.x
* 'master' of https://github.com/jclouds/jclouds: Issue 1024:Not possible to create hvm Linux nodes on Amazon Remove duplicated hexadecimal conversion code Ensure we close streams via InputSupplier methods Reduce filesystem and transient differences expect tests: removing requirement that requests are unique (so orderedRequestsSendResponses can tee up different responses for the same request when testing functions) Initial implementation of controlling SmartOS over SSH connection. Harmonize filesystem and transient putBlob remove stray @Test on base class as it's causing warnings due to its public non-test methods Issue 1011: remove PagedIterator Added optional timeout to EC2 listNodes strategy and made awaitCompletion update latch in finally block added concat to PagedIterable
This commit is contained in:
commit
00d2ac2df7
|
@ -26,7 +26,6 @@ import org.jclouds.cloudwatch.features.MetricApi;
|
|||
import org.jclouds.cloudwatch.options.ListMetricsOptions;
|
||||
import org.jclouds.collect.IterableWithMarker;
|
||||
import org.jclouds.collect.PagedIterables;
|
||||
import org.jclouds.collect.PagedIterators;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
@ -47,7 +46,7 @@ public class CloudWatch {
|
|||
* @return iterable of metrics fitting the criteria
|
||||
*/
|
||||
public static Iterable<Metric> listMetrics(final MetricApi metricApi, final ListMetricsOptions options) {
|
||||
return Iterables.concat(PagedIterables.create(PagedIterators.advancing(metricApi.list(options),
|
||||
return Iterables.concat(PagedIterables.advance(metricApi.list(options),
|
||||
new Function<Object, IterableWithMarker<Metric>>() {
|
||||
|
||||
@Override
|
||||
|
@ -59,7 +58,7 @@ public class CloudWatch {
|
|||
public String toString() {
|
||||
return "listMetrics(" + options + ")";
|
||||
}
|
||||
})));
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,8 +38,6 @@ import org.jclouds.http.HttpResponse;
|
|||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* @author Jeremy Whitlock, Adrian Cole
|
||||
*/
|
||||
|
@ -118,7 +116,7 @@ public class MetricApiExpectTest extends BaseCloudWatchApiExpectTest {
|
|||
CloudWatchApi apiWhenMetricsExist = requestsSendResponses(
|
||||
listMetrics, listMetricsResponse, listMetrics2, listMetrics2Response);
|
||||
|
||||
assertEquals(Iterables.concat(apiWhenMetricsExist.getMetricApiForRegion(null).list()).toString(),
|
||||
assertEquals(apiWhenMetricsExist.getMetricApiForRegion(null).list().concat().toString(),
|
||||
"[Metric{namespace=AWS/EC2, metricName=CPUUtilization, dimension=[Dimension{name=InstanceId, value=i-689fcf0f}]}, Metric{namespace=AWS/EC2, metricName=CPUUtilization, dimension=[Dimension{name=InstanceId, value=i-689fcf0f}]}]");
|
||||
}
|
||||
|
||||
|
|
|
@ -133,10 +133,9 @@ public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThen
|
|||
public Map<?, Future<Void>> execute(String group, int count, Template template, Set<NodeMetadata> goodNodes,
|
||||
Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
|
||||
|
||||
Template mutableTemplate = templateBuilderProvider.get().imageId(template.getImage().getId()).fromTemplate(template)
|
||||
.build();
|
||||
Template mutableTemplate = template.clone();
|
||||
|
||||
Iterable<String> ips = allocateElasticIpsInRegion(count, template);
|
||||
Iterable<String> ips = allocateElasticIpsInRegion(count, mutableTemplate);
|
||||
|
||||
Iterable<? extends RunningInstance> started = createKeyPairAndSecurityGroupsAsNeededThenRunInstances(group,
|
||||
count, mutableTemplate);
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.util.concurrent.ExecutorService;
|
|||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
@ -51,6 +50,7 @@ import com.google.common.base.Function;
|
|||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -58,10 +58,15 @@ import com.google.common.collect.ImmutableSet;
|
|||
*/
|
||||
@Singleton
|
||||
public class EC2ListNodesStrategy implements ListNodesStrategy {
|
||||
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
@Inject(optional = true)
|
||||
@Named(Constants.PROPERTY_REQUEST_TIMEOUT)
|
||||
protected static Long maxTime;
|
||||
|
||||
protected final EC2AsyncClient client;
|
||||
protected final Supplier<Set<String>> regions;
|
||||
protected final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata;
|
||||
|
@ -100,7 +105,7 @@ public class EC2ListNodesStrategy implements ListNodesStrategy {
|
|||
return castToSpecificTypedFuture(client.getInstanceServices().describeInstancesInRegion(from));
|
||||
}
|
||||
|
||||
}, executor, null, logger, "reservations");
|
||||
}, executor, maxTime, logger, "reservations");
|
||||
|
||||
return concat(concat(reservations));
|
||||
}
|
||||
|
|
|
@ -95,9 +95,7 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
strategy.autoAllocateElasticIps = true;
|
||||
|
||||
// setup expectations
|
||||
expect(templateBuilder.imageId(region + "/" + imageId)).andReturn(templateBuilder);
|
||||
expect(templateBuilder.fromTemplate(input.template)).andReturn(templateBuilder);
|
||||
expect(templateBuilder.build()).andReturn(input.template);
|
||||
expect(input.template.clone()).andReturn(input.template);
|
||||
expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce();
|
||||
expect(
|
||||
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize
|
||||
|
@ -106,7 +104,6 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
|
||||
expect(input.template.getLocation()).andReturn(input.location).atLeastOnce();
|
||||
expect(input.template.getImage()).andReturn(input.image).atLeastOnce();
|
||||
expect(input.image.getId()).andReturn(region + "/" + imageId).atLeastOnce();
|
||||
expect(input.image.getProviderId()).andReturn(imageId).atLeastOnce();
|
||||
|
||||
// differences when ip allocation
|
||||
|
@ -204,16 +201,13 @@ public class EC2CreateNodesInGroupThenAddToSetTest {
|
|||
"reservationId");
|
||||
|
||||
// setup expectations
|
||||
expect(templateBuilder.imageId(region + "/" + imageId)).andReturn(templateBuilder);
|
||||
expect(templateBuilder.fromTemplate(input.template)).andReturn(templateBuilder);
|
||||
expect(templateBuilder.build()).andReturn(input.template);
|
||||
expect(input.template.clone()).andReturn(input.template);
|
||||
expect(strategy.client.getInstanceServices()).andReturn(instanceClient).atLeastOnce();
|
||||
expect(
|
||||
strategy.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize
|
||||
.execute(region, input.tag, input.template)).andReturn(ec2Options);
|
||||
expect(input.template.getLocation()).andReturn(input.location).atLeastOnce();
|
||||
expect(input.template.getImage()).andReturn(input.image).atLeastOnce();
|
||||
expect(input.image.getId()).andReturn(region + "/" + imageId).atLeastOnce();
|
||||
expect(input.image.getProviderId()).andReturn(imageId).atLeastOnce();
|
||||
expect(instanceClient.runInstancesInRegion(region, zone, imageId, 1, input.count, ec2Options)).andReturn(
|
||||
Reservation.class.cast(reservation));
|
||||
|
|
|
@ -402,8 +402,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
}
|
||||
|
||||
public static HttpResponseException returnResponseException(int code) {
|
||||
HttpResponse response = null;
|
||||
response = HttpResponse.builder().statusCode(code).build();
|
||||
HttpResponse response = HttpResponse.builder().statusCode(code).build();
|
||||
return new HttpResponseException(new HttpCommand() {
|
||||
|
||||
public int getRedirectCount() {
|
||||
|
@ -457,17 +456,22 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
String blobKey = blob.getMetadata().getName();
|
||||
|
||||
logger.debug("Put blob with key [%s] to container [%s]", blobKey, containerName);
|
||||
String eTag = getEtag(blob);
|
||||
if (!storageStrategy.containerExists(containerName)) {
|
||||
return Futures.immediateFailedFuture(new IllegalStateException("containerName not found: " + containerName));
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO
|
||||
// must override existing file?
|
||||
|
||||
storageStrategy.writePayloadOnFile(containerName, blobKey, blob.getPayload());
|
||||
storageStrategy.putBlob(containerName, blob);
|
||||
} catch (IOException e) {
|
||||
logger.error(e, "An error occurred storing the new blob with name [%s] to container [%s].", blobKey,
|
||||
containerName);
|
||||
Throwables.propagate(e);
|
||||
}
|
||||
|
||||
String eTag = getEtag(blob);
|
||||
return immediateFuture(eTag);
|
||||
}
|
||||
|
||||
|
@ -535,7 +539,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
if (options.getRanges() != null && options.getRanges().size() > 0) {
|
||||
byte[] data;
|
||||
try {
|
||||
data = toByteArray(blob.getPayload().getInput());
|
||||
data = toByteArray(blob.getPayload());
|
||||
} catch (IOException e) {
|
||||
return immediateFailedFuture(new RuntimeException(e));
|
||||
}
|
||||
|
@ -591,13 +595,6 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
}
|
||||
}
|
||||
|
||||
private Blob copyBlob(Blob blob) {
|
||||
Blob returnVal = blobFactory.create(copy(blob.getMetadata()));
|
||||
returnVal.setPayload(blob.getPayload());
|
||||
copyPayloadHeadersToBlob(blob.getPayload(), returnVal);
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the object MD5 and returns it as eTag
|
||||
*
|
||||
|
@ -616,6 +613,13 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
return eTag;
|
||||
}
|
||||
|
||||
private Blob copyBlob(Blob blob) {
|
||||
Blob returnVal = blobFactory.create(copy(blob.getMetadata()));
|
||||
returnVal.setPayload(blob.getPayload());
|
||||
copyPayloadHeadersToBlob(blob.getPayload(), returnVal);
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean deleteAndVerifyContainerGone(final String container) {
|
||||
storageStrategy.deleteContainer(container);
|
||||
|
|
|
@ -169,11 +169,11 @@ public interface FilesystemStorageStrategy {
|
|||
void removeBlob(String container, String key);
|
||||
|
||||
/**
|
||||
* Write a {@link Blob} {@link Payload} into a file
|
||||
* @param fileName
|
||||
* @param payload
|
||||
* Write a {@link Blob} into a file
|
||||
* @param container
|
||||
* @param blob
|
||||
* @throws IOException
|
||||
*/
|
||||
void writePayloadOnFile(String container, String blobKey, Payload payload) throws IOException;
|
||||
void putBlob(String containerName, Blob blob) throws IOException;
|
||||
|
||||
}
|
||||
|
|
|
@ -204,19 +204,13 @@ public class FilesystemStorageStrategyImpl implements FilesystemStorageStrategy
|
|||
return blobFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a {@link Blob} {@link Payload} into a file
|
||||
*
|
||||
* @param container
|
||||
* @param blobKey
|
||||
* @param payload
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void writePayloadOnFile(String container, String blobKey, Payload payload) throws IOException {
|
||||
filesystemContainerNameValidator.validate(container);
|
||||
public void putBlob(final String containerName, final Blob blob) throws IOException {
|
||||
String blobKey = blob.getMetadata().getName();
|
||||
Payload payload = blob.getPayload();
|
||||
filesystemContainerNameValidator.validate(containerName);
|
||||
filesystemBlobKeyValidator.validate(blobKey);
|
||||
File outputFile = getFileForBlobKey(container, blobKey);
|
||||
File outputFile = getFileForBlobKey(containerName, blobKey);
|
||||
FileOutputStream output = null;
|
||||
try {
|
||||
Files.createParentDirs(outputFile);
|
||||
|
|
|
@ -740,6 +740,7 @@ public class FilesystemAsyncBlobStoreTest {
|
|||
* can't be deleted. See http://code.google.com/p/jclouds/issues/detail?id=737
|
||||
*/
|
||||
final String containerName = "containerWithRanges";
|
||||
blobStore.createContainerInLocation(null, containerName);
|
||||
String payload = "abcdefgh";
|
||||
InputStream is;
|
||||
Blob blob = blobStore.blobBuilder("test").payload(new StringPayload(payload)).build();
|
||||
|
|
|
@ -371,8 +371,10 @@ public class FilesystemStorageStrategyImplTest {
|
|||
blobKey = TestUtils.createRandomBlobKey("writePayload-", ".img");
|
||||
sourceFile = TestUtils.getImageForBlobPayload();
|
||||
filePayload = new FilePayload(sourceFile);
|
||||
Blob blob = storageStrategy.newBlob(blobKey);
|
||||
blob.setPayload(filePayload);
|
||||
// write files
|
||||
storageStrategy.writePayloadOnFile(CONTAINER_NAME, blobKey, filePayload);
|
||||
storageStrategy.putBlob(CONTAINER_NAME, blob);
|
||||
// verify that the files is equal
|
||||
File blobFullPath = new File(TARGET_CONTAINER_NAME, blobKey);
|
||||
InputSupplier<FileInputStream> expectedInput =
|
||||
|
|
|
@ -115,33 +115,33 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
|
||||
protected final DateService dateService;
|
||||
protected final Crypto crypto;
|
||||
protected final Provider<UriBuilder> uriBuilders;
|
||||
protected final HttpGetOptionsListToGetOptions httpGetOptionsConverter;
|
||||
protected final ContentMetadataCodec contentMetadataCodec;
|
||||
protected final IfDirectoryReturnNameStrategy ifDirectoryReturnName;
|
||||
protected final Factory blobFactory;
|
||||
protected final TransientStorageStrategy storageStrategy;
|
||||
protected final ContentMetadataCodec contentMetadataCodec;
|
||||
protected final Provider<UriBuilder> uriBuilders;
|
||||
|
||||
@Inject
|
||||
protected TransientAsyncBlobStore(BlobStoreContext context,
|
||||
DateService dateService, Crypto crypto,
|
||||
HttpGetOptionsListToGetOptions httpGetOptionsConverter,
|
||||
ContentMetadataCodec contentMetadataCodec,
|
||||
IfDirectoryReturnNameStrategy ifDirectoryReturnName,
|
||||
BlobUtils blobUtils,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service,
|
||||
Supplier<Location> defaultLocation,
|
||||
@Memoized Supplier<Set<? extends Location>> locations,
|
||||
Factory blobFactory, Provider<UriBuilder> uriBuilders,
|
||||
ContentMetadataCodec contentMetadataCodec) {
|
||||
Factory blobFactory, Provider<UriBuilder> uriBuilders) {
|
||||
super(context, blobUtils, service, defaultLocation, locations);
|
||||
this.blobFactory = blobFactory;
|
||||
this.dateService = dateService;
|
||||
this.crypto = crypto;
|
||||
this.uriBuilders = uriBuilders;
|
||||
this.httpGetOptionsConverter = httpGetOptionsConverter;
|
||||
this.contentMetadataCodec = contentMetadataCodec;
|
||||
this.ifDirectoryReturnName = ifDirectoryReturnName;
|
||||
this.storageStrategy = new TransientStorageStrategy(defaultLocation);
|
||||
this.contentMetadataCodec = contentMetadataCodec;
|
||||
this.uriBuilders = uriBuilders;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -472,7 +472,8 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
|
||||
storageStrategy.putBlob(containerName, blob);
|
||||
|
||||
return immediateFuture(Iterables.getOnlyElement(blob.getAllHeaders().get(HttpHeaders.ETAG)));
|
||||
String eTag = getEtag(blob);
|
||||
return immediateFuture(eTag);
|
||||
}
|
||||
|
||||
private Blob createUpdatedCopyOfBlobInContainer(String containerName, Blob in) {
|
||||
|
@ -579,7 +580,7 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
if (options.getRanges() != null && options.getRanges().size() > 0) {
|
||||
byte[] data;
|
||||
try {
|
||||
data = toByteArray(blob.getPayload().getInput());
|
||||
data = toByteArray(blob.getPayload());
|
||||
} catch (IOException e) {
|
||||
return immediateFailedFuture(new RuntimeException(e));
|
||||
}
|
||||
|
@ -635,6 +636,24 @@ public class TransientAsyncBlobStore extends BaseAsyncBlobStore {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the object MD5 and returns it as eTag
|
||||
*
|
||||
* @param object
|
||||
* @return
|
||||
*/
|
||||
private String getEtag(Blob object) {
|
||||
try {
|
||||
Payloads.calculateMD5(object, crypto.md5());
|
||||
} catch (IOException ex) {
|
||||
logger.error(ex, "An error occurred calculating MD5 for object with name %s.", object.getMetadata().getName());
|
||||
Throwables.propagate(ex);
|
||||
}
|
||||
|
||||
String eTag = CryptoStreams.hex(object.getPayload().getContentMetadata().getContentMD5());
|
||||
return eTag;
|
||||
}
|
||||
|
||||
private Blob copyBlob(Blob blob) {
|
||||
Blob returnVal = blobFactory.create(copy(blob.getMetadata()));
|
||||
returnVal.setPayload(blob.getPayload());
|
||||
|
|
|
@ -18,17 +18,39 @@
|
|||
*/
|
||||
package org.jclouds.collect;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.collect.UnmodifiableIterator;
|
||||
|
||||
/**
|
||||
* Extends {@link FluentIterable} allowing you to lazily advance through
|
||||
* sequence of pages in a resultset. Typically used in apis that return only a
|
||||
* certain number of records at a time.
|
||||
*
|
||||
* Simplest usage is to employ the {@link #concat} convenience function, and one
|
||||
* of the methods from {@link FluentIterable}.
|
||||
*
|
||||
* <pre>
|
||||
* // pull in new pages until it we see something interesting.
|
||||
* Optional<StorageMetadata> firstInterestingBlob = blobstore
|
||||
* .list(// options //)
|
||||
* .concat()
|
||||
* .firstMatch(isInterestingBlob());
|
||||
* </pre>
|
||||
*
|
||||
* For those seeking manual control of page advances, don't use concat, and
|
||||
* instead look at the value of {@link IterableWithMarker#nextToken}.
|
||||
*
|
||||
* <pre>
|
||||
* PagedIterator<StorageMetadata> blobs = blobstore.list(...).iterator();
|
||||
* while (blobs.hasNext()) {
|
||||
* FluentIterable<StorageMetadata> page = blobs.next();
|
||||
* IterableWithMarker<StorageMetadata> page = blobs.next();
|
||||
* ProcessedResults results = process(page);
|
||||
* if (results.shouldBeBookmarked() && blobs.nextMarker().isPresent()) {
|
||||
* saveBookmark(blobs.nextMarker().get());
|
||||
* if (results.shouldBeBookmarked() && page.nextMarker().isPresent()) {
|
||||
* saveBookmark(page.nextMarker().get());
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
|
@ -36,9 +58,39 @@ import com.google.common.collect.FluentIterable;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
@Beta
|
||||
public abstract class PagedIterable<T> extends FluentIterable<IterableWithMarker<T>> {
|
||||
public abstract class PagedIterable<E> extends FluentIterable<IterableWithMarker<E>> {
|
||||
|
||||
@Override
|
||||
public abstract PagedIterator<T> iterator();
|
||||
/**
|
||||
* Combines all the pages into a single unmodifiable iterable. ex.
|
||||
*
|
||||
* <pre>
|
||||
* FluentIterable<StorageMetadata> blobs = blobstore.list(...).concat();
|
||||
* for (StorageMetadata blob : blobs) {
|
||||
* process(blob);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see Iterators#concat
|
||||
*/
|
||||
public FluentIterable<E> concat() {
|
||||
final Iterator<IterableWithMarker<E>> iterator = iterator();
|
||||
final UnmodifiableIterator<Iterator<E>> unmodifiable = new UnmodifiableIterator<Iterator<E>>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> next() {
|
||||
return iterator.next().iterator();
|
||||
}
|
||||
};
|
||||
return new FluentIterable<E>() {
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return Iterators.concat(unmodifiable);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -18,7 +18,15 @@
|
|||
*/
|
||||
package org.jclouds.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Utilities for using {@link PagedIterable}s.
|
||||
|
@ -27,23 +35,120 @@ import com.google.common.annotations.Beta;
|
|||
*/
|
||||
@Beta
|
||||
public class PagedIterables {
|
||||
|
||||
/**
|
||||
* @param only
|
||||
* the only page of data
|
||||
*
|
||||
* @param iterator
|
||||
* how to advance pages
|
||||
*
|
||||
* @return iterable current data which continues if the user iterates beyond the first page
|
||||
* @return iterable with only the one page
|
||||
*/
|
||||
public static <T> PagedIterable<T> create(final PagedIterator<T> iterator) {
|
||||
public static <T> PagedIterable<T> of(final IterableWithMarker<T> only) {
|
||||
return new PagedIterable<T>() {
|
||||
|
||||
@Override
|
||||
public PagedIterator<T> iterator() {
|
||||
return iterator;
|
||||
public Iterator<IterableWithMarker<T>> iterator() {
|
||||
return ImmutableSet.of(only).iterator();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param initial
|
||||
* the initial set current data
|
||||
* @param markerToNext
|
||||
* produces the next set based on the marker
|
||||
*
|
||||
* @return iterable current data which continues if the user iterates beyond
|
||||
* the first page
|
||||
*/
|
||||
public static <T> PagedIterable<T> advance(final IterableWithMarker<T> initial,
|
||||
final Function<Object, IterableWithMarker<T>> markerToNext) {
|
||||
return new PagedIterable<T>() {
|
||||
|
||||
@Override
|
||||
public Iterator<IterableWithMarker<T>> iterator() {
|
||||
return advancingIterator(initial, markerToNext);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private static class AdvancingIterator<T> extends AbstractIterator<IterableWithMarker<T>> {
|
||||
|
||||
private final Function<Object, IterableWithMarker<T>> markerToNext;
|
||||
private transient IterableWithMarker<T> current;
|
||||
private transient boolean unread = true;
|
||||
|
||||
private AdvancingIterator(IterableWithMarker<T> initial, Function<Object, IterableWithMarker<T>> markerToNext) {
|
||||
this.current = checkNotNull(initial, "initial iterable");
|
||||
this.markerToNext = checkNotNull(markerToNext, "marker to next iterable");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected IterableWithMarker<T> computeNext() {
|
||||
if (unread)
|
||||
try {
|
||||
return current;
|
||||
} finally {
|
||||
unread = false;
|
||||
}
|
||||
else if (current.nextMarker().isPresent())
|
||||
return current = markerToNext.apply(current.nextMarker().get());
|
||||
else
|
||||
return endOfData();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(current, unread);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null || getClass() != obj.getClass())
|
||||
return false;
|
||||
AdvancingIterator<?> other = AdvancingIterator.class.cast(obj);
|
||||
return Objects.equal(this.current, other.current) && Objects.equal(this.unread, other.unread);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper("").add("current", current).add("unread", unread).toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param initial
|
||||
* the initial set current data
|
||||
* @param markerToNext
|
||||
* produces the next set based on the marker
|
||||
*
|
||||
* @return iterable current data which continues if the user iterates beyond
|
||||
* the first page
|
||||
*/
|
||||
public static <T> Iterator<IterableWithMarker<T>> advancingIterator(IterableWithMarker<T> initial,
|
||||
Function<Object, IterableWithMarker<T>> markerToNext) {
|
||||
if (!initial.nextMarker().isPresent()) {
|
||||
return ImmutableSet.of(initial).iterator();
|
||||
}
|
||||
return new AdvancingIterator<T>(initial, markerToNext);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,40 +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.collect;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Beta
|
||||
public abstract class PagedIterator<T> extends AbstractIterator<IterableWithMarker<T>> {
|
||||
|
||||
/**
|
||||
* If there is a next marker, then the set is incomplete and you should issue another command to
|
||||
* retrieve the rest, setting the option {@code marker} to this value
|
||||
*
|
||||
* @return next marker, or absent if list is complete
|
||||
*/
|
||||
public abstract Optional<Object> nextMarker();
|
||||
|
||||
}
|
|
@ -1,184 +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 current 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.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
/**
|
||||
* Utilities for using {@link PagedIterator}s.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Beta
|
||||
public class PagedIterators {
|
||||
|
||||
private static class AdvancingPagedIterator<T> extends PagedIterator<T> {
|
||||
|
||||
private final Function<Object, IterableWithMarker<T>> markerToNext;
|
||||
private transient IterableWithMarker<T> current;
|
||||
private transient boolean unread = true;
|
||||
|
||||
private AdvancingPagedIterator(IterableWithMarker<T> initial, Function<Object, IterableWithMarker<T>> markerToNext) {
|
||||
this.current = checkNotNull(initial, "initial iterable");
|
||||
this.markerToNext = checkNotNull(markerToNext, "marker to next iterable");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected IterableWithMarker<T> computeNext() {
|
||||
if (unread)
|
||||
try {
|
||||
return current;
|
||||
} finally {
|
||||
unread = false;
|
||||
}
|
||||
else if (nextMarker().isPresent())
|
||||
return current = markerToNext.apply(nextMarker().get());
|
||||
else
|
||||
return endOfData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Object> nextMarker() {
|
||||
return current.nextMarker();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(current, unread);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null || getClass() != obj.getClass())
|
||||
return false;
|
||||
AdvancingPagedIterator<?> other = AdvancingPagedIterator.class.cast(obj);
|
||||
return Objects.equal(this.current, other.current) && Objects.equal(this.unread, other.unread);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper("").add("current", current).add("unread", unread).toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param initial
|
||||
* the initial set current data
|
||||
* @param markerToNext
|
||||
* produces the next set based on the marker
|
||||
*
|
||||
* @return iterable current data which continues if the user iterates beyond the first page
|
||||
*/
|
||||
public static <T> PagedIterator<T> advancing(IterableWithMarker<T> initial,
|
||||
Function<Object, IterableWithMarker<T>> markerToNext) {
|
||||
if (!initial.nextMarker().isPresent()) {
|
||||
return of(initial);
|
||||
}
|
||||
return new AdvancingPagedIterator<T>(initial, markerToNext);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param initial
|
||||
* the initial set current data
|
||||
* @return iterable current data which only contains the single element
|
||||
*/
|
||||
public static <T> PagedIterator<T> of(IterableWithMarker<T> initial) {
|
||||
return new OnlyElementIterator<T>(initial);
|
||||
}
|
||||
|
||||
private static class OnlyElementIterator<T> extends PagedIterator<T> {
|
||||
|
||||
private transient IterableWithMarker<T> onlyElement;
|
||||
private transient boolean unread = true;
|
||||
|
||||
private OnlyElementIterator(IterableWithMarker<T> onlyElement) {
|
||||
this.onlyElement = checkNotNull(onlyElement, "onlyElement");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected IterableWithMarker<T> computeNext() {
|
||||
if (unread)
|
||||
try {
|
||||
return onlyElement;
|
||||
} finally {
|
||||
unread = false;
|
||||
}
|
||||
else
|
||||
return endOfData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Object> nextMarker() {
|
||||
return onlyElement.nextMarker();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(onlyElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null || getClass() != obj.getClass())
|
||||
return false;
|
||||
OnlyElementIterator<?> other = OnlyElementIterator.class.cast(obj);
|
||||
return Objects.equal(this.onlyElement, other.onlyElement) && Objects.equal(this.unread, other.unread);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper("").add("onlyElement", onlyElement).add("unread", unread).toString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,7 +40,6 @@ package org.jclouds.collect.internal;
|
|||
import org.jclouds.collect.IterableWithMarker;
|
||||
import org.jclouds.collect.PagedIterable;
|
||||
import org.jclouds.collect.PagedIterables;
|
||||
import org.jclouds.collect.PagedIterators;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.InvocationContext;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
|
@ -61,7 +60,7 @@ public abstract class CallerArg0ToPagedIterable<T, I extends CallerArg0ToPagedIt
|
|||
@Override
|
||||
public PagedIterable<T> apply(IterableWithMarker<T> input) {
|
||||
if (input.nextMarker() == null)
|
||||
return PagedIterables.create(PagedIterators.of(input));
|
||||
return PagedIterables.of(input);
|
||||
|
||||
Optional<String> arg0Option = Optional.absent();
|
||||
if (request.getCaller().get().getArgs() != null && request.getCaller().get().getArgs().length > 0) {
|
||||
|
@ -70,7 +69,7 @@ public abstract class CallerArg0ToPagedIterable<T, I extends CallerArg0ToPagedIt
|
|||
arg0Option = Optional.of(arg0.toString());
|
||||
}
|
||||
final String arg0 = arg0Option.orNull();
|
||||
return PagedIterables.create(PagedIterators.advancing(input, markerToNextForCallingArg0(arg0)));
|
||||
return PagedIterables.advance(input, markerToNextForCallingArg0(arg0));
|
||||
}
|
||||
|
||||
protected abstract Function<Object, IterableWithMarker<T>> markerToNextForCallingArg0(String arg0);
|
||||
|
|
|
@ -137,8 +137,9 @@ public class FutureIterables {
|
|||
errors.incrementAndGet();
|
||||
logException(logger, logPrefix, total, complete.get(), errors.get(), start, e);
|
||||
errorMap.put(future.getKey(), e);
|
||||
} finally {
|
||||
doneSignal.countDown();
|
||||
}
|
||||
doneSignal.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -148,10 +149,11 @@ public class FutureIterables {
|
|||
}, exec);
|
||||
}
|
||||
try {
|
||||
if (maxTime != null)
|
||||
if (maxTime != null) {
|
||||
doneSignal.await(maxTime, TimeUnit.MILLISECONDS);
|
||||
else
|
||||
} else {
|
||||
doneSignal.await();
|
||||
}
|
||||
if (errors.get() > 0) {
|
||||
String message = message(logPrefix, total, complete.get(), errors.get(), start);
|
||||
RuntimeException exception = new RuntimeException(message);
|
||||
|
|
|
@ -49,20 +49,21 @@ import com.google.common.io.InputSupplier;
|
|||
@Beta
|
||||
public class CryptoStreams {
|
||||
|
||||
public static String hex(byte[] in) {
|
||||
byte[] hex = new byte[2 * in.length];
|
||||
private static char[] hex(byte[] in, int offset, int len) {
|
||||
char[] hex = new char[2 * len];
|
||||
int index = 0;
|
||||
|
||||
for (byte b : in) {
|
||||
for (int i = offset; i < offset + len; ++i) {
|
||||
byte b = in[i];
|
||||
int v = b & 0xFF;
|
||||
hex[index++] = HEX_CHAR_TABLE[v >>> 4];
|
||||
hex[index++] = HEX_CHAR_TABLE[v & 0xF];
|
||||
}
|
||||
try {
|
||||
return new String(hex, "ASCII");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
public static String hex(byte[] in) {
|
||||
return new String(hex(in, 0, in.length));
|
||||
}
|
||||
|
||||
public static byte[] hex(String s) {
|
||||
|
@ -295,9 +296,10 @@ public class CryptoStreams {
|
|||
});
|
||||
}
|
||||
|
||||
final static byte[] HEX_CHAR_TABLE = { (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5',
|
||||
(byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e',
|
||||
(byte) 'f' };
|
||||
private final static char[] HEX_CHAR_TABLE = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
};
|
||||
|
||||
/**
|
||||
* Computes and returns the hex value for a supplied input stream.
|
||||
|
@ -313,16 +315,7 @@ public class CryptoStreams {
|
|||
final StringBuilder out = new StringBuilder();
|
||||
return com.google.common.io.ByteStreams.readBytes(supplier, new ByteProcessor<String>() {
|
||||
public boolean processBytes(byte[] buf, int off, int len) {
|
||||
char[] hex = new char[2 * len];
|
||||
int index = 0;
|
||||
|
||||
for (int i = off; i < off + len; i++) {
|
||||
byte b = buf[i];
|
||||
int v = b & 0xFF;
|
||||
hex[index++] = (char) HEX_CHAR_TABLE[v >>> 4];
|
||||
hex[index++] = (char) HEX_CHAR_TABLE[v & 0xF];
|
||||
}
|
||||
out.append(hex);
|
||||
out.append(hex(buf, off, len));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import org.testng.annotations.Test;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code IterableWithMarkers}.
|
||||
|
@ -28,7 +27,7 @@ public class PagedIterablesTest {
|
|||
|
||||
EasyMock.replay(markerToNext);
|
||||
|
||||
PagedIterable<String> iterable = PagedIterables.create(PagedIterators.advancing(initial, markerToNext));
|
||||
PagedIterable<String> iterable = PagedIterables.advance(initial, markerToNext);
|
||||
|
||||
Assert.assertSame(iterable.get(0), initial);
|
||||
|
||||
|
@ -49,9 +48,9 @@ public class PagedIterablesTest {
|
|||
|
||||
EasyMock.replay(markerToNext);
|
||||
|
||||
PagedIterable<String> iterable = PagedIterables.create(PagedIterators.advancing(initial, markerToNext));
|
||||
PagedIterable<String> iterable = PagedIterables.advance(initial, markerToNext);
|
||||
|
||||
Assert.assertEquals(ImmutableSet.copyOf(Iterables.concat(iterable)),
|
||||
Assert.assertEquals(iterable.concat().toImmutableSet(),
|
||||
ImmutableSet.of("foo", "bar", "boo", "baz", "ham", "cheeze"));
|
||||
|
||||
EasyMock.verify(markerToNext);
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
package org.jclouds.collect;
|
||||
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
|
||||
import org.easymock.EasyMock;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code IterableWithMarkers}.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(testName = "PagedIteratorsTest")
|
||||
public class PagedIteratorsTest {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testSinglePageResultReturnsSame() {
|
||||
|
||||
IterableWithMarker<String> initial = IterableWithMarkers.from(ImmutableSet.of("foo", "bar"));
|
||||
Function<Object, IterableWithMarker<String>> markerToNext = createMock(Function.class);
|
||||
|
||||
EasyMock.replay(markerToNext);
|
||||
|
||||
Assert.assertSame(PagedIterators.advancing(initial, markerToNext).next(), initial);
|
||||
|
||||
EasyMock.verify(markerToNext);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testMultiPage2Pages() {
|
||||
|
||||
IterableWithMarker<String> initial = IterableWithMarkers.from(ImmutableSet.of("foo", "bar"), "MARKER1");
|
||||
Function<Object, IterableWithMarker<String>> markerToNext = createMock(Function.class);
|
||||
|
||||
expect(markerToNext.apply("MARKER1")).andReturn(IterableWithMarkers.from(ImmutableSet.of("boo", "baz"), null));
|
||||
|
||||
EasyMock.replay(markerToNext);
|
||||
|
||||
Assert.assertEquals(ImmutableSet.copyOf(Iterables.concat(ImmutableSet.copyOf(PagedIterators.advancing(initial,
|
||||
markerToNext)))), ImmutableSet.of("foo", "bar", "boo", "baz"));
|
||||
|
||||
EasyMock.verify(markerToNext);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testMultiPage3Pages() {
|
||||
|
||||
IterableWithMarker<String> initial = IterableWithMarkers.from(ImmutableSet.of("foo", "bar"), "MARKER1");
|
||||
Function<Object, IterableWithMarker<String>> markerToNext = createMock(Function.class);
|
||||
|
||||
expect(markerToNext.apply("MARKER1")).andReturn(
|
||||
IterableWithMarkers.from(ImmutableSet.of("boo", "baz"), "MARKER2"));
|
||||
|
||||
expect(markerToNext.apply("MARKER2")).andReturn(IterableWithMarkers.from(ImmutableSet.of("ham", "cheeze"), null));
|
||||
|
||||
EasyMock.replay(markerToNext);
|
||||
|
||||
Assert.assertEquals(ImmutableSet.copyOf(Iterables.concat(ImmutableSet.copyOf(PagedIterators.advancing(initial,
|
||||
markerToNext)))), ImmutableSet.of("foo", "bar", "boo", "baz", "ham", "cheeze"));
|
||||
|
||||
EasyMock.verify(markerToNext);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testMultiPage3PagesNextMarkerSetCorrectly() {
|
||||
|
||||
IterableWithMarker<String> initial = IterableWithMarkers.from(ImmutableSet.of("foo", "bar"), "MARKER1");
|
||||
Function<Object, IterableWithMarker<String>> markerToNext = createMock(Function.class);
|
||||
IterableWithMarker<String> second = IterableWithMarkers.from(ImmutableSet.of("boo", "baz"), "MARKER2");
|
||||
expect(markerToNext.apply("MARKER1")).andReturn(second);
|
||||
IterableWithMarker<String> third = IterableWithMarkers.from(ImmutableSet.of("ham", "cheeze"), null);
|
||||
expect(markerToNext.apply("MARKER2")).andReturn(third);
|
||||
|
||||
EasyMock.replay(markerToNext);
|
||||
PagedIterator<String> iterator = PagedIterators.advancing(initial, markerToNext);
|
||||
|
||||
Assert.assertEquals(iterator.hasNext(), true);
|
||||
Assert.assertEquals(iterator.nextMarker(), Optional.of("MARKER1"));
|
||||
Assert.assertEquals(iterator.next(), initial);
|
||||
Assert.assertEquals(iterator.hasNext(), true);
|
||||
Assert.assertEquals(iterator.nextMarker(), Optional.of("MARKER2"));
|
||||
Assert.assertEquals(iterator.next(), second);
|
||||
Assert.assertEquals(iterator.hasNext(), true);
|
||||
Assert.assertEquals(iterator.nextMarker(), Optional.absent());
|
||||
Assert.assertEquals(iterator.next(), third);
|
||||
Assert.assertEquals(iterator.hasNext(), false);
|
||||
Assert.assertEquals(iterator.nextMarker(), Optional.absent());
|
||||
EasyMock.verify(markerToNext);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -80,7 +80,6 @@ import com.google.common.annotations.Beta;
|
|||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
@ -118,7 +117,6 @@ import com.google.inject.name.Names;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit")
|
||||
@Beta
|
||||
public abstract class BaseRestApiExpectTest<S> {
|
||||
|
||||
|
@ -441,13 +439,14 @@ public abstract class BaseRestApiExpectTest<S> {
|
|||
public S requestsSendResponses(final Map<HttpRequest, HttpResponse> requestToResponse, Module module,
|
||||
Properties props) {
|
||||
return createClient(new Function<HttpRequest, HttpResponse>() {
|
||||
ImmutableBiMap<HttpRequest, HttpResponse> bimap = ImmutableBiMap.copyOf(requestToResponse);
|
||||
|
||||
|
||||
@Override
|
||||
public HttpResponse apply(HttpRequest input) {
|
||||
HttpRequest matchedRequest = null;
|
||||
HttpResponse response = null;
|
||||
for (HttpRequest request : requestToResponse.keySet()) {
|
||||
if (httpRequestsAreEqual(input, request)) {
|
||||
matchedRequest = request;
|
||||
response = requestToResponse.get(request);
|
||||
}
|
||||
}
|
||||
|
@ -468,7 +467,7 @@ public abstract class BaseRestApiExpectTest<S> {
|
|||
|
||||
} else if (compareHttpRequestAsType(input) == HttpRequestComparisonType.DEFAULT) {
|
||||
// in case hashCode/equals doesn't do a full content check
|
||||
assertEquals(renderRequest(input), renderRequest(bimap.inverse().get(response)));
|
||||
assertEquals(renderRequest(input), renderRequest(matchedRequest));
|
||||
}
|
||||
|
||||
return response;
|
||||
|
|
|
@ -46,7 +46,6 @@ import org.jclouds.logging.Logger;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
|
@ -88,14 +87,13 @@ public class ELBListLoadBalancersStrategy implements ListLoadBalancersStrategy {
|
|||
|
||||
@Override
|
||||
public Iterable<LoadBalancerInRegion> apply(PagedIterable<LoadBalancer> input) {
|
||||
return Iterables.transform(Iterables.concat(input),
|
||||
new Function<LoadBalancer, LoadBalancerInRegion>() {
|
||||
|
||||
@Override
|
||||
public LoadBalancerInRegion apply(LoadBalancer lb) {
|
||||
return new LoadBalancerInRegion(lb, from);
|
||||
}
|
||||
});
|
||||
return input.concat()
|
||||
.transform(new Function<LoadBalancer, LoadBalancerInRegion>() {
|
||||
@Override
|
||||
public LoadBalancerInRegion apply(LoadBalancer lb) {
|
||||
return new LoadBalancerInRegion(lb, from);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}, executor);
|
||||
|
|
|
@ -145,7 +145,7 @@ public class LoadBalancerApiExpectTest extends BaseELBApiExpectTest {
|
|||
LoadBalancer lb1 = new GetLoadBalancerResponseTest().expected().toBuilder().name("my-load-balancer-1").build();
|
||||
LoadBalancer lb2 = new GetLoadBalancerResponseTest().expected();
|
||||
|
||||
assertEquals(ImmutableSet.copyOf(Iterables.concat(apiWhenExist.getLoadBalancerApi().list())), ImmutableSet.of(lb1, lb2));
|
||||
assertEquals(apiWhenExist.getLoadBalancerApi().list().concat().toImmutableSet(), ImmutableSet.of(lb1, lb2));
|
||||
}
|
||||
|
||||
public void testList2PagesWhenResponseIs2xxInEU() throws Exception {
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.jclouds.elb.loadbalancer;
|
|||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import org.jclouds.collect.PagedIterable;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.elb.ELBApi;
|
||||
import org.jclouds.elb.ELBAsyncApi;
|
||||
|
@ -30,9 +29,9 @@ import org.jclouds.rest.RestContext;
|
|||
import org.jclouds.sshj.config.SshjSshClientModule;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSet.Builder;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -61,8 +60,8 @@ public class ELBLoadBalancerServiceLiveTest extends BaseLoadBalancerServiceLiveT
|
|||
instanceIds.add(node.getProviderId());
|
||||
}
|
||||
|
||||
PagedIterable<LoadBalancer> elbs = elbApi.getLoadBalancerApi().list();
|
||||
for (LoadBalancer elb : Iterables.concat(elbs)) {
|
||||
FluentIterable<LoadBalancer> elbs = elbApi.getLoadBalancerApi().list().concat();
|
||||
for (LoadBalancer elb : elbs) {
|
||||
if (elb.getName().equals(group))
|
||||
assertEquals(elb.getInstanceIds(), instanceIds.build());
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ public class UserApiExpectTest extends BaseIAMApiExpectTest {
|
|||
|
||||
IAMApi apiWhenExist = requestsSendResponses(list, listResponse, list2, list2Response);
|
||||
|
||||
assertEquals(ImmutableList.copyOf(Iterables.concat(apiWhenExist.getUserApi().list())),
|
||||
assertEquals(apiWhenExist.getUserApi().list().concat().toImmutableList(),
|
||||
ImmutableList.copyOf(Iterables.concat(new ListUsersResponseTest().expected(), new ListUsersResponseTest().expected())));
|
||||
}
|
||||
|
||||
|
|
|
@ -55,5 +55,6 @@
|
|||
<module>nodepool</module>
|
||||
<module>rds</module>
|
||||
<module>aws-rds</module>
|
||||
<module>smartos-ssh</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
|
@ -140,7 +140,7 @@ public class InstanceApiExpectTest extends BaseRDSApiExpectTest {
|
|||
RDSApi apiWhenExist = requestsSendResponses(
|
||||
list, listResponse, list2, list2Response);
|
||||
|
||||
assertEquals(ImmutableList.copyOf(Iterables.concat(apiWhenExist.getInstanceApi().list())),
|
||||
assertEquals(apiWhenExist.getInstanceApi().list().concat().toImmutableList(),
|
||||
ImmutableList.copyOf(Iterables.concat(new DescribeDBInstancesResponseTest().expected(),
|
||||
new DescribeDBInstancesResponseTest().expected())));
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ public class SecurityGroupApiExpectTest extends BaseRDSApiExpectTest {
|
|||
RDSApi apiWhenExist = requestsSendResponses(
|
||||
list, listResponse, list2, list2Response);
|
||||
|
||||
assertEquals(ImmutableList.copyOf(Iterables.concat(apiWhenExist.getSecurityGroupApi().list())),
|
||||
assertEquals(apiWhenExist.getSecurityGroupApi().list().concat().toImmutableList(),
|
||||
ImmutableList.copyOf(Iterables.concat(new DescribeDBSecurityGroupsResponseTest().expected(),
|
||||
new DescribeDBSecurityGroupsResponseTest().expected())));
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ public class SubnetGroupApiExpectTest extends BaseRDSApiExpectTest {
|
|||
RDSApi apiWhenExist = requestsSendResponses(
|
||||
list, listResponse, list2, list2Response);
|
||||
|
||||
assertEquals(ImmutableList.copyOf(Iterables.concat(apiWhenExist.getSubnetGroupApi().list())),
|
||||
assertEquals(apiWhenExist.getSubnetGroupApi().list().concat().toImmutableList(),
|
||||
ImmutableList.copyOf(Iterables.concat(new DescribeDBSubnetGroupsResponseTest().expected(),
|
||||
new DescribeDBSubnetGroupsResponseTest().expected())));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
This is designed for interacting with a Joyent SmartOS host, in order to be able to leverage
|
||||
the lightweight VM support (nee Solaris Zones).
|
||||
|
||||
It is planned to support KVM VMs in the future.
|
||||
|
||||
--------------
|
||||
|
||||
#Setup
|
||||
|
||||
Have a SmartOS installation, that you know either the root password for, or a secondary account with sufficient
|
||||
permissions to be able to run the vm tools (vmadm, dsadm).
|
||||
|
||||
That's it!
|
||||
|
||||
--------------
|
||||
|
||||
#Notes:
|
||||
|
||||
- This is a work in progress, so please report any bugs that you find.
|
|
@ -0,0 +1,121 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-project</artifactId>
|
||||
<version>1.5.0-SNAPSHOT</version>
|
||||
<relativePath>../../project/pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>org.jclouds.labs</groupId>
|
||||
<artifactId>smartos-ssh</artifactId>
|
||||
<name>smartos ssh api</name>
|
||||
<description>jclouds components to access SmartOS over SSH</description>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<properties>
|
||||
<test.smartos-ssh.endpoint>https://api.joyentcloud.com</test.smartos-ssh.endpoint>
|
||||
<test.smartos-ssh.api-version>~6.5</test.smartos-ssh.api-version>
|
||||
<test.smartos-ssh.build-version></test.smartos-ssh.build-version>
|
||||
<test.smartos-ssh.identity>FIXME_IDENTITY</test.smartos-ssh.identity>
|
||||
<test.smartos-ssh.credential>FIXME_CREDENTIALS</test.smartos-ssh.credential>
|
||||
<jclouds.osgi.export>org.jclouds.joyent.cloudapi.v6_5*;version="${project.version}"</jclouds.osgi.export>
|
||||
<jclouds.osgi.import>
|
||||
org.jclouds.rest.internal;version="${project.version}",
|
||||
org.jclouds*;version="${project.version}",
|
||||
*
|
||||
</jclouds.osgi.import>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-compute</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-compute</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jclouds</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jclouds.driver</groupId>
|
||||
<artifactId>jclouds-slf4j</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jclouds.driver</groupId>
|
||||
<artifactId>jclouds-sshj</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>live</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>integration</id>
|
||||
<phase>integration-test</phase>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<test.smartos-ssh.endpoint>${test.smartos-ssh.endpoint}</test.smartos-ssh.endpoint>
|
||||
<test.smartos-ssh.api-version>${test.smartos-ssh.api-version}</test.smartos-ssh.api-version>
|
||||
<test.smartos-ssh.build-version>${test.smartos-ssh.build-version}</test.smartos-ssh.build-version>
|
||||
<test.smartos-ssh.identity>${test.smartos-ssh.identity}</test.smartos-ssh.identity>
|
||||
<test.smartos-ssh.credential>${test.smartos-ssh.credential}</test.smartos-ssh.credential>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,57 @@
|
|||
package org.jclouds.smartos;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.jclouds.apis.ApiMetadata;
|
||||
import org.jclouds.apis.internal.BaseApiMetadata;
|
||||
import org.jclouds.compute.ComputeServiceContext;
|
||||
import org.jclouds.smartos.compute.config.SmartOSComputeServiceContextModule;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ApiMetadata} for SmartOS
|
||||
*
|
||||
* @author Nigel Magnay
|
||||
*/
|
||||
public class SmartOSApiMetadata extends BaseApiMetadata {
|
||||
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = 3606170564482119304L;
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return Builder.class.cast(builder().fromApiMetadata(this));
|
||||
}
|
||||
|
||||
public SmartOSApiMetadata() {
|
||||
super(builder());
|
||||
}
|
||||
|
||||
protected SmartOSApiMetadata(Builder builder) {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
public static class Builder extends BaseApiMetadata.Builder {
|
||||
|
||||
protected Builder(){
|
||||
id("smartos-ssh")
|
||||
.name("SmartOS SSH API")
|
||||
.identityName("Username")
|
||||
.defaultIdentity("root")
|
||||
.defaultCredential("smartos")
|
||||
.defaultEndpoint("http://localhost")
|
||||
.documentation(URI.create("http://http://wiki.smartos.org/display/DOC/How+to+create+a+Virtual+Machine+in+SmartOS"))
|
||||
.view(ComputeServiceContext.class)
|
||||
.defaultModule(SmartOSComputeServiceContextModule.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmartOSApiMetadata build() {
|
||||
return new SmartOSApiMetadata(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* 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.smartos.compute.config;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import org.jclouds.smartos.compute.domain.DataSet;
|
||||
import org.jclouds.smartos.compute.domain.SmartOSHost;
|
||||
import org.jclouds.smartos.compute.domain.VM;
|
||||
import org.jclouds.smartos.compute.domain.VmSpecification;
|
||||
import org.jclouds.compute.ComputeServiceAdapter;
|
||||
import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.domain.Location;
|
||||
|
||||
import org.jclouds.smartos.compute.functions.DataSetToImage;
|
||||
import org.jclouds.smartos.compute.functions.DatacenterToLocation;
|
||||
import org.jclouds.smartos.compute.functions.VMToNodeMetadata;
|
||||
import org.jclouds.smartos.compute.functions.VmSpecificationToHardware;
|
||||
import org.jclouds.smartos.compute.strategy.SmartOSComputeServiceAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nigel Magnay
|
||||
*/
|
||||
public class SmartOSComputeServiceContextModule extends
|
||||
ComputeServiceAdapterContextModule<VM, VmSpecification, DataSet, SmartOSHost> {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
super.configure();
|
||||
bind(new TypeLiteral<ComputeServiceAdapter<VM, VmSpecification, DataSet, SmartOSHost>>() {
|
||||
}).to(SmartOSComputeServiceAdapter.class);
|
||||
bind(new TypeLiteral<Function<VM, NodeMetadata>>() {
|
||||
}).to(VMToNodeMetadata.class);
|
||||
bind(new TypeLiteral<Function<DataSet, org.jclouds.compute.domain.Image>>() {
|
||||
}).to(DataSetToImage.class);
|
||||
bind(new TypeLiteral<Function<VmSpecification, org.jclouds.compute.domain.Hardware>>() {
|
||||
}).to(VmSpecificationToHardware.class);
|
||||
bind(new TypeLiteral<Function<SmartOSHost, Location>>() {
|
||||
}).to(DatacenterToLocation.class);
|
||||
// to have the compute service adapter override default locations
|
||||
//install(new LocationsFromComputeServiceAdapterModule<VM, VmSpecification, DataSet, SmartOSHost>(){});
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
package org.jclouds.smartos.compute.domain;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Dataset is a pre-built image ready to be cloned.
|
||||
*/
|
||||
public class DataSet {
|
||||
private final UUID uuid;
|
||||
private final String os;
|
||||
private final String published;
|
||||
private final String urn;
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public Builder toBuilder() {
|
||||
return builder().fromDataSet(this);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
public UUID uuid;
|
||||
public String os;
|
||||
public String published;
|
||||
public String urn;
|
||||
|
||||
public Builder uuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder uuid(String uuid) {
|
||||
this.uuid = UUID.fromString(uuid);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder os(String os) {
|
||||
this.os = os;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder published(String published) {
|
||||
this.published = published;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder urn(String urn) {
|
||||
this.urn = urn;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fromDsadmString(String string) {
|
||||
String [] sections = string.split(" ");
|
||||
|
||||
uuid ( sections[0] );
|
||||
os ( sections[1] );
|
||||
published ( sections[2] );
|
||||
urn ( sections[3] );
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DataSet build() {
|
||||
return new DataSet(uuid, os, published, urn);
|
||||
}
|
||||
|
||||
public Builder fromDataSet(DataSet in) {
|
||||
return uuid(in.getUuid())
|
||||
.os(in.getOs())
|
||||
.published(in.getPublished())
|
||||
.urn(in.getUrn());
|
||||
}
|
||||
}
|
||||
|
||||
protected DataSet(UUID uuid, String os, String published, String urn) {
|
||||
this.uuid = uuid;
|
||||
this.os = os;
|
||||
this.published = published;
|
||||
this.urn = urn;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public String getOs() {
|
||||
return os;
|
||||
}
|
||||
|
||||
public String getPublished() {
|
||||
return published;
|
||||
}
|
||||
|
||||
public String getUrn() {
|
||||
return urn;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// UUID is primary key
|
||||
return uuid.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
return uuid.equals(((DataSet)obj).uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this).omitNullValues()
|
||||
.add("uuid", uuid)
|
||||
.add("os", os)
|
||||
.add("published", published)
|
||||
.add("urn", urn).toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,296 @@
|
|||
package org.jclouds.smartos.compute.domain;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.net.HostAndPort;
|
||||
import org.jclouds.domain.LoginCredentials;
|
||||
import org.jclouds.location.Provider;
|
||||
import org.jclouds.rest.annotations.Credential;
|
||||
import org.jclouds.rest.annotations.Identity;
|
||||
import org.jclouds.ssh.SshClient;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A host machine that runs smartOS
|
||||
*/
|
||||
@Singleton
|
||||
public class SmartOSHost {
|
||||
protected final String hostname;
|
||||
protected final String username;
|
||||
protected final String password;
|
||||
|
||||
protected SshClient.Factory sshClientFactory;
|
||||
|
||||
private SshClient _connection;
|
||||
|
||||
public static class HostException extends RuntimeException {
|
||||
public HostException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
|
||||
public HostException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
|
||||
public static class NoResponseException extends Exception {
|
||||
public NoResponseException() {
|
||||
}
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public Builder toBuilder() {
|
||||
return builder().fromSmartOSHost(this);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
protected String hostname;
|
||||
protected String username;
|
||||
protected String password;
|
||||
protected SshClient.Factory sshFactory;
|
||||
|
||||
public Builder hostname(String hostname) {
|
||||
this.hostname = hostname;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder username(String username) {
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder password(String password) {
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder sshFactory(SshClient.Factory sshFactory) {
|
||||
this.sshFactory = sshFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SmartOSHost build() {
|
||||
return new SmartOSHost(hostname, username, password, sshFactory);
|
||||
}
|
||||
|
||||
public Builder fromSmartOSHost(SmartOSHost in) {
|
||||
return this.hostname ( in.getHostname() )
|
||||
.username ( in.getHostname() )
|
||||
.password ( in.getPassword() )
|
||||
.sshFactory( in.getSshClientFactory() );
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected SmartOSHost(@Provider Supplier<URI> provider,
|
||||
@Nullable @Identity String identity,
|
||||
@Nullable @Credential String credential,
|
||||
SshClient.Factory sshFactory) {
|
||||
|
||||
this.hostname = provider.get().getHost();
|
||||
this.username = identity;
|
||||
this.password = credential;
|
||||
this.sshClientFactory = sshFactory;
|
||||
}
|
||||
|
||||
protected SmartOSHost(String hostname, String username, String password, SshClient.Factory sshClientFactory) {
|
||||
this.hostname = hostname;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.sshClientFactory = sshClientFactory;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return "SmartOS@" + hostname;
|
||||
}
|
||||
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public SshClient.Factory getSshClientFactory() {
|
||||
return sshClientFactory;
|
||||
}
|
||||
|
||||
protected SshClient getConnection() {
|
||||
if (_connection == null) {
|
||||
|
||||
LoginCredentials credentials = new LoginCredentials.Builder()
|
||||
.user(username)
|
||||
.password(password)
|
||||
.build();
|
||||
|
||||
_connection = getSshClientFactory().create(
|
||||
HostAndPort.fromParts(hostname, 22),
|
||||
credentials
|
||||
);
|
||||
|
||||
_connection.connect();
|
||||
|
||||
}
|
||||
return _connection;
|
||||
}
|
||||
|
||||
|
||||
public String exec(String cmd) {
|
||||
return getConnection().exec(cmd).getOutput();
|
||||
}
|
||||
|
||||
public String vmList() {
|
||||
return exec("vmadm list -p");
|
||||
}
|
||||
|
||||
|
||||
public Map<String, String> getVMIpAddresses(UUID vmId)
|
||||
{
|
||||
ImmutableMap.Builder<String, String> netMapBuilder = ImmutableMap.builder();
|
||||
|
||||
String response = getConnection().exec("zlogin " + vmId.toString() + " ifconfig -a4").getOutput();
|
||||
|
||||
if( response.length() == 0)
|
||||
return ImmutableMap.of();
|
||||
|
||||
Iterable<String> strings = Splitter.on("\n").split(response);
|
||||
Pattern inetMatcher = Pattern.compile("inet [0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}");
|
||||
|
||||
String iface = "";
|
||||
for(String line : strings )
|
||||
{
|
||||
if( line.length() > 0 && Character.isLetterOrDigit(line.charAt(0)) )
|
||||
{
|
||||
iface = line.substring(0, line.indexOf(":") );
|
||||
}
|
||||
else
|
||||
{
|
||||
Matcher matcher = inetMatcher.matcher(line);
|
||||
if( matcher.find() )
|
||||
netMapBuilder.put(iface, matcher.group().substring(5));
|
||||
}
|
||||
}
|
||||
|
||||
return netMapBuilder.build();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* What remotely available images are there in the cloud?
|
||||
*
|
||||
* @return Collection of datasets
|
||||
*/
|
||||
public Iterable<DataSet> getAvailableImages() {
|
||||
return toSpecList(exec("dsadm avail"));
|
||||
}
|
||||
|
||||
public Iterable<DataSet> getLocalDatasets() {
|
||||
return toSpecList(exec("dsadm list"));
|
||||
}
|
||||
|
||||
public Iterable<VM> getVMs() {
|
||||
return toVMList(exec("vmadm list -p"));
|
||||
}
|
||||
|
||||
public VM createVM(VmSpecification specification) {
|
||||
|
||||
String response = getConnection().exec("(cat <<END\n" +
|
||||
specification.toJSONSpecification() + "\nEND\n) | vmadm create").getOutput();
|
||||
|
||||
Pattern uuidPattern = Pattern.compile("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}");
|
||||
Matcher matcher = uuidPattern.matcher(response);
|
||||
if (matcher.find()) {
|
||||
String uuid = matcher.group();
|
||||
return getVM( UUID.fromString(uuid) );
|
||||
} else {
|
||||
throw new HostException("Error creating Host: response = " + response + "\n source = " + specification.toJSONSpecification());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Iterable<DataSet> toSpecList(String string) {
|
||||
|
||||
try {
|
||||
BufferedReader r = new BufferedReader(new StringReader(string));
|
||||
r.readLine(); // Skip
|
||||
String line;
|
||||
ImmutableList.Builder resultBuilder = ImmutableList.builder();
|
||||
while ((line = r.readLine()) != null) {
|
||||
DataSet dataset = DataSet.builder().fromDsadmString(line).build();
|
||||
|
||||
resultBuilder.add(dataset);
|
||||
}
|
||||
return resultBuilder.build();
|
||||
} catch (IOException e) {
|
||||
throw new HostException("Error parsing response when building spec list", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Iterable<VM> toVMList(String string) {
|
||||
try {
|
||||
BufferedReader r = new BufferedReader(new StringReader(string));
|
||||
String line;
|
||||
ImmutableList.Builder resultBuilder = ImmutableList.builder();
|
||||
while ((line = r.readLine()) != null) {
|
||||
VM vm = VM.builder().host(this).fromVmadmString(line).build();
|
||||
|
||||
resultBuilder.add(vm);
|
||||
}
|
||||
return resultBuilder.build();
|
||||
} catch (IOException e) {
|
||||
throw new HostException("Error parsing response when building VM list", e);
|
||||
}
|
||||
}
|
||||
|
||||
public VM getVM(UUID serverId) {
|
||||
for (VM vm : getVMs())
|
||||
if (vm.uuid.equals(serverId))
|
||||
return vm;
|
||||
return null;
|
||||
}
|
||||
|
||||
public DataSet getDataSet(UUID imageId) {
|
||||
for (DataSet ds : getLocalDatasets()) {
|
||||
if (ds.getUuid().equals(imageId))
|
||||
return ds;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void destroyHost(UUID uuid) {
|
||||
exec("vmadm delete " + uuid.toString());
|
||||
}
|
||||
|
||||
public void rebootHost(UUID uuid) {
|
||||
exec("vmadm reboot " + uuid.toString());
|
||||
}
|
||||
|
||||
public void stopHost(UUID uuid) {
|
||||
exec("vmadm stop -p");
|
||||
}
|
||||
|
||||
public void startHost(UUID uuid) {
|
||||
exec("vmadm start " + uuid.toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
package org.jclouds.smartos.compute.domain;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Representing a Virtual Machine (Zone / KVM )
|
||||
**/
|
||||
public class VM {
|
||||
|
||||
public enum State
|
||||
{
|
||||
RUNNING,
|
||||
STOPPED,
|
||||
INCOMPLETE
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public Builder toBuilder() {
|
||||
return builder().fromVM(this);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
protected SmartOSHost host;
|
||||
protected UUID uuid;
|
||||
protected String type;
|
||||
protected String ram;
|
||||
protected State state = State.STOPPED;
|
||||
protected String alias;
|
||||
|
||||
public Builder uuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder uuid(String uuid) {
|
||||
this.uuid = UUID.fromString(uuid);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder host(SmartOSHost host) {
|
||||
this.host = host;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder type(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder ram(String ram) {
|
||||
this.ram = ram;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder state(String state) {
|
||||
this.state = State.valueOf(state.toUpperCase());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder state(State state) {
|
||||
this.state = state;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder alias(String alias) {
|
||||
this.alias = alias;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fromVmadmString(String string) {
|
||||
String[] sections = string.split(":");
|
||||
|
||||
uuid(sections[0]);
|
||||
|
||||
type(sections[1]);
|
||||
ram(sections[2]);
|
||||
state(sections[3]);
|
||||
|
||||
if (sections.length > 4)
|
||||
alias(sections[4]);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public VM build() {
|
||||
return new VM(host,uuid,type,ram,state,alias);
|
||||
}
|
||||
|
||||
public Builder fromVM(VM in) {
|
||||
return host(in.getHost())
|
||||
.uuid(in.getUuid())
|
||||
.type(in.getType())
|
||||
.ram(in.getRam())
|
||||
.state(in.getState())
|
||||
.alias(in.getAlias());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected SmartOSHost host;
|
||||
protected final UUID uuid;
|
||||
protected String type;
|
||||
protected String ram;
|
||||
protected State state;
|
||||
protected String alias;
|
||||
|
||||
|
||||
public VM(SmartOSHost host, UUID uuid, String type, String ram, State state, String alias) {
|
||||
this.host = host;
|
||||
this.uuid = uuid;
|
||||
this.type = type;
|
||||
this.ram = ram;
|
||||
this.state = state;
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
host.destroyHost(uuid);
|
||||
}
|
||||
|
||||
public void reboot() {
|
||||
host.rebootHost(uuid);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
host.stopHost(uuid);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
host.startHost(uuid);
|
||||
}
|
||||
|
||||
public Optional<String> getPublicAddress() throws InterruptedException {
|
||||
Map<String, String> ipAddresses;
|
||||
|
||||
for( int i=0; i<30; i++ )
|
||||
{
|
||||
ipAddresses = host.getVMIpAddresses(uuid);
|
||||
if( ipAddresses.isEmpty() )
|
||||
{
|
||||
// Got some
|
||||
String ip = ipAddresses.get("net0");
|
||||
if( ip != null && !ip.equals("0.0.0.0"))
|
||||
return Optional.of(ip);
|
||||
}
|
||||
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
public SmartOSHost getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getRam() {
|
||||
return ram;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// UUID is primary key
|
||||
return uuid.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
return uuid.equals(((DataSet)obj).getUuid());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this).omitNullValues()
|
||||
.add("uuid", uuid)
|
||||
.add("type", type)
|
||||
.add("ram", ram)
|
||||
.add("alias", alias).toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package org.jclouds.smartos.compute.domain;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.google.inject.name.Named;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
/**
|
||||
* Specification of a network card.
|
||||
*/
|
||||
public class VmNIC {
|
||||
|
||||
@SerializedName("nic_tag")
|
||||
protected final String tag;
|
||||
protected final String ip;
|
||||
protected final String netmask;
|
||||
protected final String gateway;
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public Builder toBuilder() {
|
||||
return builder().fromVmNIC(this);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
public String tag = "admin";
|
||||
public String ip;
|
||||
public String netmask;
|
||||
public String gateway;
|
||||
|
||||
|
||||
public Builder simpleDCHPNic() {
|
||||
tag = "admin";
|
||||
ip = "dhcp";
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder tag(String tag) {
|
||||
this.tag = tag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder ip(String ip) {
|
||||
this.ip = ip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder netmask(String netmask) {
|
||||
this.netmask = netmask;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder gateway(String gateway) {
|
||||
this.gateway = gateway;
|
||||
return this;
|
||||
}
|
||||
|
||||
public VmNIC build() {
|
||||
return new VmNIC(tag,ip,netmask,gateway);
|
||||
}
|
||||
|
||||
public Builder fromVmNIC(VmNIC in) {
|
||||
return tag ( in.getTag())
|
||||
.ip ( in.getIp() )
|
||||
.netmask( in.getNetmask() )
|
||||
.gateway( in.getGateway() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public VmNIC(String tag, String ip, String netmask, String gateway) {
|
||||
this.tag = tag;
|
||||
this.ip = ip;
|
||||
this.netmask = netmask;
|
||||
this.gateway = gateway;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public String getNetmask() {
|
||||
return netmask;
|
||||
}
|
||||
|
||||
public String getGateway() {
|
||||
return gateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this).omitNullValues()
|
||||
.add("tag", tag)
|
||||
.add("ip", ip)
|
||||
.add("netmask", netmask)
|
||||
.add("gateway", gateway).toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
package org.jclouds.smartos.compute.domain;
|
||||
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Specification of a VM to build, based on a dataset.
|
||||
*/
|
||||
public class VmSpecification {
|
||||
protected final String alias;
|
||||
protected final String brand;
|
||||
|
||||
@SerializedName("dataset_uuid")
|
||||
protected final DataSet dataset;
|
||||
protected final String dnsDomain;
|
||||
protected final String quota;
|
||||
|
||||
protected final List<VmNIC> nics;
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public Builder toBuilder() {
|
||||
return builder().fromVmSpecification(this);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
protected String alias;
|
||||
protected String brand = "joyent";
|
||||
protected DataSet dataset;
|
||||
protected String dnsDomain = "local";
|
||||
protected String quota = "10";
|
||||
|
||||
protected List<VmNIC> nics = new ArrayList<VmNIC>();
|
||||
|
||||
public Builder alias(String alias) {
|
||||
this.alias = alias;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder brand(String brand) {
|
||||
this.brand = brand;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder dataset(DataSet dataset) {
|
||||
this.dataset = dataset;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder dnsDomain(String dnsDomain) {
|
||||
this.dnsDomain = dnsDomain;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder quota(String quota) {
|
||||
this.quota = quota;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder nics(Collection<VmNIC> nic) {
|
||||
this.nics.addAll(nics);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder nic(VmNIC nic) {
|
||||
this.nics.add(nic);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VmSpecification build() {
|
||||
return new VmSpecification(alias, brand, dataset, dnsDomain, quota, nics);
|
||||
}
|
||||
|
||||
public Builder fromVmSpecification(VmSpecification in) {
|
||||
return alias (in.getAlias())
|
||||
.brand (in.getBrand())
|
||||
.dataset (in.getDataset())
|
||||
.dnsDomain(in.getDnsDomain())
|
||||
.quota (in.getQuota())
|
||||
.nics(in.getNics());
|
||||
}
|
||||
}
|
||||
|
||||
protected VmSpecification(String alias, String brand, DataSet dataset, String dnsDomain, String quota, List<VmNIC> nics) {
|
||||
this.alias = alias;
|
||||
this.brand = brand;
|
||||
this.dataset = dataset;
|
||||
this.dnsDomain = dnsDomain;
|
||||
this.quota = quota;
|
||||
this.nics = nics;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public String getBrand() {
|
||||
return brand;
|
||||
}
|
||||
|
||||
public DataSet getDataset() {
|
||||
return dataset;
|
||||
}
|
||||
|
||||
public String getDnsDomain() {
|
||||
return dnsDomain;
|
||||
}
|
||||
|
||||
public String getQuota() {
|
||||
return quota;
|
||||
}
|
||||
|
||||
public List<VmNIC> getNics() {
|
||||
return ImmutableList.copyOf(nics);
|
||||
}
|
||||
|
||||
public String toJSONSpecification() {
|
||||
GsonBuilder gson = new GsonBuilder();
|
||||
gson.registerTypeAdapter(DataSet.class, new FlattenDataset() );
|
||||
Gson g = gson.create();
|
||||
|
||||
return g.toJson(this);
|
||||
}
|
||||
|
||||
public class FlattenDataset implements JsonSerializer<DataSet>
|
||||
{
|
||||
@Override
|
||||
public JsonElement serialize(DataSet vmSpecification, Type type, JsonSerializationContext jsonSerializationContext) {
|
||||
return new JsonPrimitive(dataset.getUuid().toString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* 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.smartos.compute.functions;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.smartos.compute.domain.DataSet;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.domain.ImageBuilder;
|
||||
import org.jclouds.compute.domain.OperatingSystem;
|
||||
import org.jclouds.compute.domain.OsFamily;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* @author Nigel Magnay
|
||||
*/
|
||||
@Singleton
|
||||
public class DataSetToImage implements Function<DataSet, Image> {
|
||||
@Resource
|
||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
@Override
|
||||
public Image apply(DataSet from) {
|
||||
|
||||
ImageBuilder builder = new ImageBuilder();
|
||||
builder.ids(from.getUuid() + "");
|
||||
builder.name(from.getUrn());
|
||||
builder.description(from.getUrn());
|
||||
builder.status(Image.Status.AVAILABLE);
|
||||
|
||||
OsFamily family;
|
||||
try {
|
||||
family = OsFamily.SOLARIS;
|
||||
builder.operatingSystem(new OperatingSystem.Builder().name(from.getUrn()).description(from.getUrn()).family(family).build());
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.debug("<< didn't match os(%s)", from);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* 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.smartos.compute.functions;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import org.jclouds.smartos.compute.domain.SmartOSHost;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.domain.LocationBuilder;
|
||||
import org.jclouds.domain.LocationScope;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* @author Nigel Magnay
|
||||
*/
|
||||
@Singleton
|
||||
public class DatacenterToLocation implements Function<SmartOSHost, Location> {
|
||||
private final Provider<Supplier<Location>> provider;
|
||||
|
||||
// allow us to lazy discover the provider of a resource
|
||||
@Inject
|
||||
public DatacenterToLocation(Provider<Supplier<Location>> provider) {
|
||||
this.provider = checkNotNull(provider, "provider");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location apply(SmartOSHost from) {
|
||||
return new LocationBuilder().scope(LocationScope.ZONE).id(from.getHostname() + "").description(from.getDescription()).parent(
|
||||
provider.get().get()).build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
/**
|
||||
* 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.smartos.compute.functions;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.sun.corba.se.spi.activation.Server;
|
||||
import org.jclouds.smartos.compute.domain.VM;
|
||||
import org.jclouds.collect.FindResourceInSet;
|
||||
import org.jclouds.collect.Memoized;
|
||||
import org.jclouds.compute.domain.*;
|
||||
import org.jclouds.compute.functions.GroupNamingConvention;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.domain.LoginCredentials;
|
||||
import org.omg.PortableInterceptor.ACTIVE;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* @author Nigel Magnay
|
||||
*/
|
||||
@Singleton
|
||||
public class VMToNodeMetadata implements Function<VM, NodeMetadata> {
|
||||
|
||||
public static final Map<VM.State, NodeMetadata.Status> serverStatusToNodeStatus = ImmutableMap
|
||||
.<VM.State, NodeMetadata.Status> builder()
|
||||
.put(VM.State.RUNNING, NodeMetadata.Status.RUNNING)//
|
||||
.put(VM.State.STOPPED, NodeMetadata.Status.SUSPENDED)//
|
||||
.put(VM.State.INCOMPLETE, NodeMetadata.Status.PENDING)//
|
||||
.build();
|
||||
|
||||
private final FindHardwareForServer findHardwareForServer;
|
||||
private final FindLocationForServer findLocationForServer;
|
||||
private final FindImageForServer findImageForServer;
|
||||
private final Map<String, Credentials> credentialStore;
|
||||
private final GroupNamingConvention nodeNamingConvention;
|
||||
|
||||
@Inject
|
||||
VMToNodeMetadata(Map<String, Credentials> credentialStore, FindHardwareForServer findHardwareForServer,
|
||||
FindLocationForServer findLocationForServer, FindImageForServer findImageForServer,
|
||||
GroupNamingConvention.Factory namingConvention) {
|
||||
this.nodeNamingConvention = checkNotNull(namingConvention, "namingConvention").createWithoutPrefix();
|
||||
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
|
||||
this.findHardwareForServer = checkNotNull(findHardwareForServer, "findHardwareForServer");
|
||||
this.findLocationForServer = checkNotNull(findLocationForServer, "findLocationForServer");
|
||||
this.findImageForServer = checkNotNull(findImageForServer, "findImageForServer");
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeMetadata apply(VM from) {
|
||||
// convert the result object to a jclouds NodeMetadata
|
||||
NodeMetadataBuilder builder = new NodeMetadataBuilder();
|
||||
builder.ids(from.getUuid() + "");
|
||||
builder.name(from.getAlias());
|
||||
builder.location(findLocationForServer.apply(from));
|
||||
builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getType()));
|
||||
builder.imageId(from.getType() + "");
|
||||
Image image = findImageForServer.apply(from);
|
||||
if (image != null)
|
||||
builder.operatingSystem(image.getOperatingSystem());
|
||||
builder.hardware(findHardwareForServer.apply(from));
|
||||
builder.status(serverStatusToNodeStatus.get(from.getState()));
|
||||
try {
|
||||
if( from.getState() == VM.State.RUNNING )
|
||||
{
|
||||
Optional<String> ip = from.getPublicAddress();
|
||||
if( ip.isPresent() ) {
|
||||
builder.publicAddresses(ImmutableSet.<String> of(ip.get()));
|
||||
builder.privateAddresses(ImmutableSet.<String> of(ip.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
// None?
|
||||
}
|
||||
//builder.privateAddresses(ImmutableSet.<String> of(from.privateAddress));
|
||||
builder.credentials(LoginCredentials.fromCredentials(credentialStore.get(from.getUuid() + "")));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class FindHardwareForServer extends FindResourceInSet<VM, Hardware> {
|
||||
|
||||
@Inject
|
||||
public FindHardwareForServer(@Memoized Supplier<Set<? extends Hardware>> hardware) {
|
||||
super(hardware);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(VM from, Hardware input) {
|
||||
return input.getProviderId().equals(from.getUuid() + "");
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class FindImageForServer extends FindResourceInSet<VM, Image> {
|
||||
|
||||
@Inject
|
||||
public FindImageForServer(@Memoized Supplier<Set<? extends Image>> hardware) {
|
||||
super(hardware);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(VM from, Image input) {
|
||||
return input.getProviderId().equals(from.getUuid() + "");
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class FindLocationForServer extends FindResourceInSet<VM, Location> {
|
||||
|
||||
@Inject
|
||||
public FindLocationForServer(@Memoized Supplier<Set<? extends Location>> hardware) {
|
||||
super(hardware);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(VM from, Location input) {
|
||||
return input.getId().equals(from.getUuid() + "");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* 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.smartos.compute.functions;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.smartos.compute.domain.VmSpecification;
|
||||
import org.jclouds.compute.domain.Hardware;
|
||||
import org.jclouds.compute.domain.HardwareBuilder;
|
||||
import org.jclouds.compute.domain.Processor;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* @author Nigel Magnay
|
||||
*/
|
||||
@Singleton
|
||||
public class VmSpecificationToHardware implements Function<VmSpecification, Hardware> {
|
||||
|
||||
@Override
|
||||
public Hardware apply(VmSpecification from) {
|
||||
HardwareBuilder builder = new HardwareBuilder();
|
||||
builder.ids("AnID");
|
||||
builder.name(from.getAlias());
|
||||
builder.processors(ImmutableList.of(new Processor(1, 1.0)));
|
||||
builder.ram(256);
|
||||
//builder.volumes(ImmutableList.<Volume> of(new VolumeImpl(from.disk, true, false)));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/**
|
||||
* 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.smartos.compute.strategy;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.smartos.compute.domain.*;
|
||||
import org.jclouds.compute.ComputeService;
|
||||
import org.jclouds.compute.ComputeServiceAdapter;
|
||||
import org.jclouds.compute.domain.Template;
|
||||
import org.jclouds.domain.LoginCredentials;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* defines the connection between the {@link org.jclouds.smartos.compute.domain.SmartOSHost} implementation and the jclouds
|
||||
* {@link ComputeService}
|
||||
*
|
||||
*/
|
||||
@Singleton
|
||||
public class SmartOSComputeServiceAdapter implements ComputeServiceAdapter<VM, VmSpecification, DataSet, SmartOSHost> {
|
||||
private final SmartOSHost host;
|
||||
|
||||
@Inject
|
||||
public SmartOSComputeServiceAdapter(SmartOSHost host) {
|
||||
this.host = checkNotNull(host, "host");
|
||||
}
|
||||
|
||||
private SmartOSHost getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeAndInitialCredentials<VM> createNodeWithGroupEncodedIntoName(String tag, String name, Template template) {
|
||||
VmSpecification specification = VmSpecification.builder()
|
||||
.alias(name)
|
||||
.dataset(getHost().getDataSet(UUID.fromString(template.getImage().getProviderId())))
|
||||
.nic(VmNIC.builder().simpleDCHPNic().build())
|
||||
.build();
|
||||
|
||||
VM from = getHost().createVM(specification);
|
||||
|
||||
return new NodeAndInitialCredentials<VM>(from, from.getUuid() + "", LoginCredentials.builder().user("smartos")
|
||||
.password("smartos").build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<VmSpecification> listHardwareProfiles() {
|
||||
List<VmSpecification> specificationList = new ArrayList<VmSpecification>();
|
||||
|
||||
VmSpecification vs = VmSpecification.builder()
|
||||
.alias("Standard Joyent VM")
|
||||
.nic(VmNIC.builder().simpleDCHPNic().build())
|
||||
.build();
|
||||
|
||||
specificationList.add(vs);
|
||||
|
||||
return specificationList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<DataSet> listImages() {
|
||||
return getHost().getLocalDatasets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSet getImage(String id) {
|
||||
return getHost().getDataSet(UUID.fromString(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<VM> listNodes() {
|
||||
return getHost().getVMs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<SmartOSHost> listLocations() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VM getNode(String id) {
|
||||
return getHost().getVM(UUID.fromString(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyNode(String id) {
|
||||
getHost().getVM(UUID.fromString(id)).destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rebootNode(String id) {
|
||||
getHost().getVM(UUID.fromString(id)).reboot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resumeNode(String id) {
|
||||
getHost().getVM(UUID.fromString(id)).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suspendNode(String id) {
|
||||
getHost().getVM(UUID.fromString(id)).stop();
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.jclouds.smartos.SmartOSApiMetadata
|
|
@ -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.smartos.compute;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Module;
|
||||
import org.jclouds.ContextBuilder;
|
||||
import org.jclouds.compute.ComputeServiceContext;
|
||||
import org.jclouds.internal.ContextImpl;
|
||||
import org.jclouds.rest.internal.BaseRestClientTest;
|
||||
import org.jclouds.smartos.SmartOSApiMetadata;
|
||||
import org.jclouds.sshj.config.SshjSshClientModule;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
@Test(groups = "unit", testName = "ServerManagerContextBuilderTest")
|
||||
public class SmartOSManagerComputeServiceContextBuilderTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void testCanBuildWithApiMetadata() {
|
||||
ComputeServiceContext context = ContextBuilder.newBuilder(
|
||||
new SmartOSApiMetadata())
|
||||
.modules(ImmutableSet.<Module>of(getSshModule()))
|
||||
.build(ComputeServiceContext.class);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanBuildById() {
|
||||
ComputeServiceContext context = ContextBuilder.newBuilder("smartos-ssh")
|
||||
.modules(ImmutableSet.<Module>of(getSshModule()))
|
||||
.build(ComputeServiceContext.class);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanBuildWithOverridingProperties() {
|
||||
Properties overrides = new Properties();
|
||||
overrides.setProperty("smartos-ssh.endpoint", "http://host");
|
||||
overrides.setProperty("smartos-ssh.api-version", "1");
|
||||
|
||||
ComputeServiceContext context = ContextBuilder.newBuilder("smartos-ssh")
|
||||
.modules(ImmutableSet.<Module>of(getSshModule()))
|
||||
.overrides(overrides).build(ComputeServiceContext.class);
|
||||
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnwrapIsCorrectType() {
|
||||
ComputeServiceContext context = ContextBuilder.newBuilder("smartos-ssh")
|
||||
.modules(ImmutableSet.<Module>of(getSshModule()))
|
||||
.build(ComputeServiceContext.class);
|
||||
|
||||
assertEquals(context.unwrap().getClass(), ContextImpl.class);
|
||||
|
||||
context.close();
|
||||
}
|
||||
|
||||
protected Module getSshModule() {
|
||||
return new SshjSshClientModule();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.smartos.compute;
|
||||
|
||||
import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.domain.OsFamily;
|
||||
import org.jclouds.compute.domain.Template;
|
||||
import org.jclouds.compute.internal.BaseComputeServiceLiveTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "live", enabled = true, singleThreaded = true)
|
||||
public class SmartOSManagerComputeServiceLiveTest extends BaseComputeServiceLiveTest {
|
||||
|
||||
public SmartOSManagerComputeServiceLiveTest() {
|
||||
provider = "smartos-ssh";
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTemplateBuilder() {
|
||||
Template defaultTemplate = client.templateBuilder().build();
|
||||
assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
|
||||
assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "5.3");
|
||||
assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.CENTOS);
|
||||
assertEquals(defaultTemplate.getLocation().getId(), "1");
|
||||
assertEquals(getCores(defaultTemplate.getHardware()), 0.5d);
|
||||
}
|
||||
|
||||
|
||||
// smartos-ssh does not support metadata
|
||||
@Override
|
||||
protected void checkUserMetadataInNodeEquals(NodeMetadata node, ImmutableMap<String, String> userMetadata) {
|
||||
assert node.getUserMetadata().equals(ImmutableMap.<String, String> of()) : String.format(
|
||||
"node userMetadata did not match %s %s", userMetadata, node);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package org.jclouds.smartos.compute.domain;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Test(groups = "unit", testName = "DataSetTest")
|
||||
public class DataSetTest {
|
||||
|
||||
@Test
|
||||
public void testParse() throws IOException {
|
||||
// Response from console from a 'dsadm list'
|
||||
InputStream is = getClass().getResourceAsStream("dsadm-list-response.txt");
|
||||
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(is));
|
||||
String line = r.readLine(); // skip line
|
||||
ImmutableList.Builder resultBuilder = ImmutableList.builder();
|
||||
while ((line = r.readLine()) != null) {
|
||||
DataSet ds = DataSet.builder().fromDsadmString(line).build();
|
||||
|
||||
resultBuilder.add(ds);
|
||||
}
|
||||
List<DataSet> dataSetList = resultBuilder.build();
|
||||
|
||||
Assert.assertEquals(10, dataSetList.size());
|
||||
|
||||
Assert.assertEquals(UUID.fromString("c0ffee88-883e-47cf-80d1-ad71cc872180"), dataSetList.get(0).getUuid());
|
||||
Assert.assertEquals("nrm:nrm:realtime-jenkins:1.7", dataSetList.get(0).getUrn());
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package org.jclouds.smartos.compute.domain;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Test(groups = "unit", testName = "VMTest")
|
||||
public class VMTest {
|
||||
|
||||
@Test
|
||||
public void testParse() throws IOException {
|
||||
// Response from console from a 'vmadm list -p'
|
||||
InputStream is = getClass().getResourceAsStream("vmadm-list-response.txt");
|
||||
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(is));
|
||||
String line = null;
|
||||
ImmutableList.Builder resultBuilder = ImmutableList.builder();
|
||||
while ((line = r.readLine()) != null) {
|
||||
VM vm = VM.builder().fromVmadmString(line).build();
|
||||
|
||||
resultBuilder.add(vm);
|
||||
}
|
||||
List<VM> vmList = resultBuilder.build();
|
||||
|
||||
Assert.assertEquals(2, vmList.size());
|
||||
|
||||
Assert.assertEquals(UUID.fromString("60bd2ae5-4e4d-4952-88f9-1b850259d914"), vmList.get(0).getUuid());
|
||||
Assert.assertEquals(VM.State.STOPPED, vmList.get(0).getState());
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
|
||||
|
||||
<!--
|
||||
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">
|
||||
|
||||
|
||||
<appender name="S" class="org.apache.log4j.ConsoleAppender">
|
||||
|
||||
<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="WIREFILE" class="org.apache.log4j.DailyRollingFileAppender">
|
||||
<param name="File" value="target/test-data/jclouds-wire.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="FILE" class="org.apache.log4j.DailyRollingFileAppender">
|
||||
<param name="File" value="target/test-data/jclouds.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="BLOBSTOREFILE" class="org.apache.log4j.DailyRollingFileAppender">
|
||||
<param name="File" value="target/test-data/jclouds-blobstore.log"/>
|
||||
<param name="Append" value="true"/>
|
||||
<param name="DatePattern" value="'.'yyyy-MM-dd"/>
|
||||
<param name="Threshold" value="TRACE"/>
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %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>
|
||||
|
||||
<appender name="ASYNCWIRE" class="org.apache.log4j.AsyncAppender">
|
||||
<appender-ref ref="WIREFILE"/>
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNCBLOBSTORE" class="org.apache.log4j.AsyncAppender">
|
||||
<appender-ref ref="BLOBSTOREFILE"/>
|
||||
</appender>
|
||||
<!-- ================ -->
|
||||
<!-- Limit categories -->
|
||||
<!-- ================ -->
|
||||
|
||||
<category name="org.jclouds">
|
||||
<priority value="DEBUG"/>
|
||||
<appender-ref ref="ASYNC"/>
|
||||
</category>
|
||||
|
||||
<category name="jclouds.headers">
|
||||
<priority value="DEBUG"/>
|
||||
<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.blobstore">
|
||||
<priority value="DEBUG"/>
|
||||
<appender-ref ref="ASYNCBLOBSTORE"/>
|
||||
</category>
|
||||
<category name="jclouds.compute">
|
||||
<priority value="TRACE"/>
|
||||
<appender-ref ref="ASYNCCOMPUTE"/>
|
||||
</category>
|
||||
<!-- ======================= -->
|
||||
<!-- Setup the Root category -->
|
||||
<!-- ======================= -->
|
||||
|
||||
<root>
|
||||
<priority value="TRACE"/>
|
||||
<appender-ref ref="S"/>
|
||||
</root>
|
||||
|
||||
</log4j:configuration>
|
|
@ -0,0 +1,11 @@
|
|||
UUID OS PUBLISHED URN
|
||||
c0ffee88-883e-47cf-80d1-ad71cc872180 smartos 2012-05-02 nrm:nrm:realtime-jenkins:1.7
|
||||
c0ffee99-883e-47cf-80d1-ad71cc872180 smartos 2012-05-02 nrm:nrm:realtime-jenkins:1.7
|
||||
bb5aa3d2-cc19-11e1-99e7-a752418da63a smartos 2012-05-02 nrm:nrm:jenkins-slave:1.0
|
||||
c0ffee32-883e-47cf-80d1-ad71cc872180 smartos 2012-05-02 nrm:nrm:realtime-jenkins:1.6.3
|
||||
467ca742-4873-11e1-80ea-37290b38d2eb smartos 2012-02-14 sdc:sdc:smartos64:1.5.3
|
||||
56108678-1183-11e1-83c3-ff3185a5b47f linux 2011-11-18 sdc:sdc:ubuntu10.04:0.1.0
|
||||
f9e4be48-9466-11e1-bc41-9f993f5dff36 smartos 2012-05-02 sdc:sdc:smartos64:1.6.3
|
||||
c0ffee64-883e-47cf-80d1-ad71cc872180 smartos 2012-05-02 nrm:nrm:realtime-jenkins:1.6
|
||||
a9380908-ea0e-11e0-aeee-4ba794c83c33 smartos 2011-09-28 sdc:sdc:percona:1.0.7
|
||||
c0ffee00-883e-47cf-80d1-ad71cc872180 smartos 2012-05-02 sdc:sdc:realtime-jenkins:1.6.3
|
|
@ -0,0 +1,2 @@
|
|||
60bd2ae5-4e4d-4952-88f9-1b850259d914:OS:256:stopped:
|
||||
a8799014-7680-481f-b7de-76b501dbd803:OS:256:running:instance1-3b5
|
|
@ -29,7 +29,6 @@ import java.util.Set;
|
|||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
@ -45,6 +44,7 @@ import org.jclouds.location.Region;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -76,7 +76,7 @@ public class AWSEC2ListNodesStrategy extends EC2ListNodesStrategy {
|
|||
.describeSpotInstanceRequestsInRegion(from);
|
||||
}
|
||||
|
||||
}, executor, null, logger, "reservations")), spotConverter), notNull());
|
||||
}, executor, maxTime, logger, "reservations")), spotConverter), notNull());
|
||||
|
||||
return concat(super.pollRunningInstances(), spots);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue