mirror of https://github.com/apache/jclouds.git
JCLOUDS-138. Add CloudStackImageExtension support.
This commit is contained in:
parent
ccb4323986
commit
a906f9f4ec
|
@ -31,6 +31,7 @@ import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.jclouds.cloudstack.CloudStackClient;
|
import org.jclouds.cloudstack.CloudStackClient;
|
||||||
import org.jclouds.cloudstack.compute.CloudStackComputeService;
|
import org.jclouds.cloudstack.compute.CloudStackComputeService;
|
||||||
|
import org.jclouds.cloudstack.compute.extensions.CloudStackImageExtension;
|
||||||
import org.jclouds.cloudstack.compute.functions.OrphanedGroupsByZoneId;
|
import org.jclouds.cloudstack.compute.functions.OrphanedGroupsByZoneId;
|
||||||
import org.jclouds.cloudstack.compute.functions.ServiceOfferingToHardware;
|
import org.jclouds.cloudstack.compute.functions.ServiceOfferingToHardware;
|
||||||
import org.jclouds.cloudstack.compute.functions.TemplateToImage;
|
import org.jclouds.cloudstack.compute.functions.TemplateToImage;
|
||||||
|
@ -73,6 +74,7 @@ import org.jclouds.compute.ComputeServiceAdapter;
|
||||||
import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
|
import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
|
||||||
import org.jclouds.compute.domain.NodeMetadata;
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
import org.jclouds.compute.domain.OperatingSystem;
|
import org.jclouds.compute.domain.OperatingSystem;
|
||||||
|
import org.jclouds.compute.extensions.ImageExtension;
|
||||||
import org.jclouds.compute.options.TemplateOptions;
|
import org.jclouds.compute.options.TemplateOptions;
|
||||||
import org.jclouds.domain.Location;
|
import org.jclouds.domain.Location;
|
||||||
import org.jclouds.rest.AuthorizationException;
|
import org.jclouds.rest.AuthorizationException;
|
||||||
|
@ -80,6 +82,7 @@ import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExc
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
@ -136,6 +139,9 @@ public class CloudStackComputeServiceContextModule extends
|
||||||
bind(new TypeLiteral<Function<Set<? extends NodeMetadata>, Multimap<String, String>>>() {
|
bind(new TypeLiteral<Function<Set<? extends NodeMetadata>, Multimap<String, String>>>() {
|
||||||
}).to(OrphanedGroupsByZoneId.class);
|
}).to(OrphanedGroupsByZoneId.class);
|
||||||
|
|
||||||
|
bind(new TypeLiteral<ImageExtension>() {
|
||||||
|
}).to(CloudStackImageExtension.class);
|
||||||
|
|
||||||
// to have the compute service adapter override default locations
|
// to have the compute service adapter override default locations
|
||||||
install(new LocationsFromComputeServiceAdapterModule<VirtualMachine, ServiceOffering, Template, Zone>(){});
|
install(new LocationsFromComputeServiceAdapterModule<VirtualMachine, ServiceOffering, Template, Zone>(){});
|
||||||
}
|
}
|
||||||
|
@ -252,4 +258,10 @@ public class CloudStackComputeServiceContextModule extends
|
||||||
NetworkType.ADVANCED, new AdvancedNetworkOptionsConverter(),
|
NetworkType.ADVANCED, new AdvancedNetworkOptionsConverter(),
|
||||||
NetworkType.BASIC, new BasicNetworkOptionsConverter());
|
NetworkType.BASIC, new BasicNetworkOptionsConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Optional<ImageExtension> provideImageExtension(Injector i) {
|
||||||
|
return Optional.of(i.getInstance(ImageExtension.class));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF 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.cloudstack.compute.extensions;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
import static com.google.common.collect.Iterables.find;
|
||||||
|
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE;
|
||||||
|
import static org.jclouds.location.predicates.LocationPredicates.idEquals;
|
||||||
|
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.Constants;
|
||||||
|
import org.jclouds.cloudstack.CloudStackClient;
|
||||||
|
import org.jclouds.cloudstack.domain.AsyncCreateResponse;
|
||||||
|
import org.jclouds.cloudstack.domain.Template;
|
||||||
|
import org.jclouds.cloudstack.domain.TemplateMetadata;
|
||||||
|
import org.jclouds.cloudstack.domain.VirtualMachine;
|
||||||
|
import org.jclouds.cloudstack.domain.Volume;
|
||||||
|
import org.jclouds.cloudstack.options.CreateTemplateOptions;
|
||||||
|
import org.jclouds.cloudstack.options.ListVolumesOptions;
|
||||||
|
import org.jclouds.cloudstack.strategy.BlockUntilJobCompletesAndReturnResult;
|
||||||
|
import org.jclouds.collect.Memoized;
|
||||||
|
import org.jclouds.compute.domain.CloneImageTemplate;
|
||||||
|
import org.jclouds.compute.domain.Image;
|
||||||
|
import org.jclouds.compute.domain.ImageBuilder;
|
||||||
|
import org.jclouds.compute.domain.ImageTemplate;
|
||||||
|
import org.jclouds.compute.domain.ImageTemplateBuilder;
|
||||||
|
import org.jclouds.compute.domain.OperatingSystem;
|
||||||
|
import org.jclouds.compute.extensions.ImageExtension;
|
||||||
|
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||||
|
import org.jclouds.domain.Location;
|
||||||
|
import org.jclouds.logging.Logger;
|
||||||
|
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.util.concurrent.Atomics;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||||
|
import com.google.common.util.concurrent.UncheckedTimeoutException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CloudStack implementation of {@link ImageExtension}
|
||||||
|
*
|
||||||
|
* @author Andrew Bayer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class CloudStackImageExtension implements ImageExtension {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||||
|
protected Logger logger = Logger.NULL;
|
||||||
|
|
||||||
|
private final CloudStackClient client;
|
||||||
|
private final ListeningExecutorService userExecutor;
|
||||||
|
private final Supplier<Set<? extends Location>> locations;
|
||||||
|
private final Predicate<AtomicReference<Image>> imageAvailablePredicate;
|
||||||
|
private final BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult;
|
||||||
|
private final Predicate<String> jobComplete;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public CloudStackImageExtension(CloudStackClient client,
|
||||||
|
@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
|
||||||
|
@Memoized Supplier<Set<? extends Location>> locations,
|
||||||
|
@Named(TIMEOUT_IMAGE_AVAILABLE) Predicate<AtomicReference<Image>> imageAvailablePredicate,
|
||||||
|
BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult,
|
||||||
|
Predicate<String> jobComplete) {
|
||||||
|
this.client = checkNotNull(client, "client");
|
||||||
|
this.userExecutor = checkNotNull(userExecutor, "userExecutor");
|
||||||
|
this.locations = checkNotNull(locations, "locations");
|
||||||
|
this.imageAvailablePredicate = checkNotNull(imageAvailablePredicate, "imageAvailablePredicate");
|
||||||
|
this.blockUntilJobCompletesAndReturnResult = checkNotNull(blockUntilJobCompletesAndReturnResult,
|
||||||
|
"blockUntilJobCompletesAndReturnResult");
|
||||||
|
this.jobComplete = checkNotNull(jobComplete, "jobComplete");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImageTemplate buildImageTemplateFromNode(String name, String id) {
|
||||||
|
VirtualMachine vm = client.getVirtualMachineClient().getVirtualMachine(id);
|
||||||
|
if (vm == null)
|
||||||
|
throw new NoSuchElementException("Cannot find vm with id: " + id);
|
||||||
|
CloneImageTemplate template = new ImageTemplateBuilder.CloneImageTemplateBuilder().nodeId(id).name(name).build();
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<Image> createImage(ImageTemplate template) {
|
||||||
|
checkState(template instanceof CloneImageTemplate,
|
||||||
|
" cloudstack only currently supports creating images through cloning.");
|
||||||
|
CloneImageTemplate cloneTemplate = (CloneImageTemplate) template;
|
||||||
|
|
||||||
|
VirtualMachine vm = client.getVirtualMachineClient().getVirtualMachine(cloneTemplate.getSourceNodeId());
|
||||||
|
String stopJob = client.getVirtualMachineClient().stopVirtualMachine(vm.getId());
|
||||||
|
jobComplete.apply(stopJob);
|
||||||
|
|
||||||
|
Set<Volume> volumes = client.getVolumeClient().listVolumes(ListVolumesOptions.Builder.virtualMachineId(vm.getId()));
|
||||||
|
Volume volume = Iterables.getOnlyElement(volumes);
|
||||||
|
|
||||||
|
CreateTemplateOptions options = CreateTemplateOptions.Builder.volumeId(volume.getId());
|
||||||
|
AsyncCreateResponse templateJob = client.getTemplateClient().createTemplate(TemplateMetadata.builder()
|
||||||
|
.name(cloneTemplate.getName())
|
||||||
|
.osTypeId(vm.getGuestOSId())
|
||||||
|
.displayText(cloneTemplate.getName())
|
||||||
|
.build(), options);
|
||||||
|
Template newTemplate = blockUntilJobCompletesAndReturnResult.<Template>apply(templateJob);
|
||||||
|
|
||||||
|
logger.info(">> Registered new template %s, waiting for it to become available.", newTemplate.getId());
|
||||||
|
|
||||||
|
final AtomicReference<Image> image = Atomics.newReference(new ImageBuilder()
|
||||||
|
.location(find(locations.get(), idEquals(vm.getZoneId())))
|
||||||
|
.id(newTemplate.getId())
|
||||||
|
.providerId(newTemplate.getId())
|
||||||
|
.description(cloneTemplate.getName())
|
||||||
|
.operatingSystem(OperatingSystem.builder().description(cloneTemplate.getName()).build())
|
||||||
|
.status(Image.Status.PENDING).build());
|
||||||
|
|
||||||
|
return userExecutor.submit(new Callable<Image>() {
|
||||||
|
@Override
|
||||||
|
public Image call() throws Exception {
|
||||||
|
if (imageAvailablePredicate.apply(image))
|
||||||
|
return image.get();
|
||||||
|
// TODO: get rid of the expectation that the image will be available, as it is very brittle
|
||||||
|
throw new UncheckedTimeoutException("Image was not created within the time limit: " + image.get());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteImage(String id) {
|
||||||
|
try {
|
||||||
|
AsyncCreateResponse deleteJob = client.getTemplateClient().deleteTemplate(id);
|
||||||
|
jobComplete.apply(deleteJob.getJobId());
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,200 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF 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.cloudstack.compute.extensions;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.jclouds.cloudstack.CloudStackContext;
|
||||||
|
import org.jclouds.cloudstack.compute.CloudStackComputeService;
|
||||||
|
import org.jclouds.cloudstack.internal.BaseCloudStackComputeServiceContextExpectTest;
|
||||||
|
import org.jclouds.compute.ComputeService;
|
||||||
|
import org.jclouds.compute.ComputeServiceContext;
|
||||||
|
import org.jclouds.compute.domain.Image;
|
||||||
|
import org.jclouds.compute.domain.ImageTemplate;
|
||||||
|
import org.jclouds.compute.extensions.ImageExtension;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.http.HttpResponse;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableMap.Builder;
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import com.google.inject.Injector;
|
||||||
|
import com.google.inject.Module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Andrew Bayer
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", testName = "CloudStackImageExtensionExpectTest")
|
||||||
|
public class CloudStackImageExtensionExpectTest extends BaseCloudStackComputeServiceContextExpectTest<ComputeService> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Properties setupProperties() {
|
||||||
|
Properties overrides = super.setupProperties();
|
||||||
|
overrides.setProperty("jclouds.zones", "MTV-Zone1");
|
||||||
|
return overrides;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateImage() {
|
||||||
|
HttpRequest listVM = HttpRequest.builder().method("GET")
|
||||||
|
.endpoint("http://localhost:8080/client/api")
|
||||||
|
.addQueryParam("response", "json")
|
||||||
|
.addQueryParam("command", "listVirtualMachines")
|
||||||
|
.addQueryParam("listAll", "true")
|
||||||
|
.addQueryParam("id", "3239ade9-fd25-405c-8eda-59f0313a3fb0")
|
||||||
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
|
.addQueryParam("signature", "Qq7Br3qNsyr5ifWZHIrLAslhwm0%3D")
|
||||||
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse listVMResponse = HttpResponse.builder().statusCode(200)
|
||||||
|
.payload(payloadFromResource("/listvirtualmachinesresponse-imageextension.json"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpRequest stopVM = HttpRequest.builder().method("GET")
|
||||||
|
.endpoint("http://localhost:8080/client/api")
|
||||||
|
.addQueryParam("response", "json")
|
||||||
|
.addQueryParam("command", "stopVirtualMachine")
|
||||||
|
.addQueryParam("id", "3239ade9-fd25-405c-8eda-59f0313a3fb0")
|
||||||
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
|
.addQueryParam("signature", "y9vxRK61K8sDoWtvSJHIx5WO9AE%3D")
|
||||||
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse stopVMResponse = HttpResponse.builder().statusCode(200)
|
||||||
|
.payload(payloadFromResource("/stopvirtualmachineresponse-imageextension.json"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpRequest stopAsyncJobResult = HttpRequest.builder().method("GET")
|
||||||
|
.endpoint("http://localhost:8080/client/api")
|
||||||
|
.addQueryParam("response", "json")
|
||||||
|
.addQueryParam("command", "queryAsyncJobResult")
|
||||||
|
.addQueryParam("jobid", "a7d5127b-24a2-4a44-a4a7-25a6d057b453")
|
||||||
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
|
.addQueryParam("signature", "CVpnN%2FSbx%2FMCOOyj%2FoVAt3bn684%3D")
|
||||||
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse stopAsyncJobResultResponse = HttpResponse.builder().statusCode(200)
|
||||||
|
.payload(payloadFromResource("/queryasyncjobresultresponse-stopvirtualmachine-imageextension.json"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpRequest listVolumes = HttpRequest.builder().method("GET")
|
||||||
|
.endpoint("http://localhost:8080/client/api")
|
||||||
|
.addQueryParam("response", "json")
|
||||||
|
.addQueryParam("command", "listVolumes")
|
||||||
|
.addQueryParam("listAll", "true")
|
||||||
|
.addQueryParam("virtualmachineid", "3239ade9-fd25-405c-8eda-59f0313a3fb0")
|
||||||
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
|
.addQueryParam("signature", "drLPf9NE9ROZPOfeDkASiKa50t8%3D")
|
||||||
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse listVolumesResponse = HttpResponse.builder().statusCode(200)
|
||||||
|
.payload(payloadFromResource("/listvolumesresponse-imageextension.json"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
HttpRequest createTemplate = HttpRequest.builder().method("GET")
|
||||||
|
.endpoint("http://localhost:8080/client/api")
|
||||||
|
.addQueryParam("response", "json")
|
||||||
|
.addQueryParam("command", "createTemplate")
|
||||||
|
.addQueryParam("volumeid", "fe1ada16-57a0-40ae-b577-01a153690fb4")
|
||||||
|
.addQueryParam("name", "temp-template-ignore")
|
||||||
|
.addQueryParam("ostypeid", "45de18f1-87c6-4646-8099-95c61f2a300a")
|
||||||
|
.addQueryParam("displaytext", "temp-template-ignore")
|
||||||
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
|
.addQueryParam("signature", "madHsBgxjYbM6JnZKYWajOlfPlY%3D")
|
||||||
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse createTemplateResponse = HttpResponse.builder().statusCode(200)
|
||||||
|
.payload(payloadFromResource("/createtemplateresponse-imageextension.json"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpRequest createAsyncJobResult = HttpRequest.builder().method("GET")
|
||||||
|
.endpoint("http://localhost:8080/client/api")
|
||||||
|
.addQueryParam("response", "json")
|
||||||
|
.addQueryParam("command", "queryAsyncJobResult")
|
||||||
|
.addQueryParam("jobid", "4e345230-8fcc-48a3-8a37-c5fe960df671")
|
||||||
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
|
.addQueryParam("signature", "6mTKL9fjz7bn6C7tOaZBzKdZwHs%3D")
|
||||||
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse createAsyncJobResultResponse = HttpResponse.builder().statusCode(200)
|
||||||
|
.payload(payloadFromResource("/queryasyncjobresultresponse-createtemplate-imageextension.json"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpRequest getTemplate = HttpRequest.builder().method("GET")
|
||||||
|
.endpoint("http://localhost:8080/client/api")
|
||||||
|
.addQueryParam("response", "json")
|
||||||
|
.addQueryParam("command", "listTemplates")
|
||||||
|
.addQueryParam("listAll", "true")
|
||||||
|
.addQueryParam("templatefilter", "executable")
|
||||||
|
.addQueryParam("id", "3dc6ce25-a6cf-4d60-a664-3499993b511b")
|
||||||
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
|
.addQueryParam("signature", "dXv%2Bl04EDd7hmrWv5CdW8v298RE%3D")
|
||||||
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse getTemplateResponse = HttpResponse.builder().statusCode(200)
|
||||||
|
.payload(payloadFromResource("/listtemplatesresponse-imageextension.json"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
|
||||||
|
.put(listTemplates, listTemplatesResponse)
|
||||||
|
.put(listOsTypes, listOsTypesResponse)
|
||||||
|
.put(listOsCategories, listOsCategoriesResponse)
|
||||||
|
.put(listZones, listZonesResponse)
|
||||||
|
.put(listServiceOfferings, listServiceOfferingsResponse)
|
||||||
|
.put(listAccounts, listAccountsResponse)
|
||||||
|
.put(listNetworks, listNetworksResponse)
|
||||||
|
.put(getZone, getZoneResponse)
|
||||||
|
.put(listVM, listVMResponse)
|
||||||
|
.put(stopVM, stopVMResponse)
|
||||||
|
.put(stopAsyncJobResult, stopAsyncJobResultResponse)
|
||||||
|
.put(listVolumes, listVolumesResponse)
|
||||||
|
.put(createTemplate, createTemplateResponse)
|
||||||
|
.put(createAsyncJobResult, createAsyncJobResultResponse)
|
||||||
|
.put(getTemplate, getTemplateResponse)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ImageExtension apiThatCreatesImage = requestsSendResponses(requestResponseMap).getImageExtension().get();
|
||||||
|
|
||||||
|
ImageTemplate newImageTemplate = apiThatCreatesImage.buildImageTemplateFromNode("temp-template-ignore", "3239ade9-fd25-405c-8eda-59f0313a3fb0");
|
||||||
|
|
||||||
|
Image image = Futures.getUnchecked(apiThatCreatesImage.createImage(newImageTemplate));
|
||||||
|
assertEquals(image.getId(), "3dc6ce25-a6cf-4d60-a664-3499993b511b");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComputeService createClient(Function<HttpRequest, HttpResponse> fn, Module module, Properties props) {
|
||||||
|
return clientFrom(createInjector(fn, module, props).getInstance(CloudStackContext.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ComputeService clientFrom(CloudStackContext context) {
|
||||||
|
return context.getComputeService();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF 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.cloudstack.compute.extensions;
|
||||||
|
|
||||||
|
import org.jclouds.compute.extensions.ImageExtension;
|
||||||
|
import org.jclouds.compute.extensions.internal.BaseImageExtensionLiveTest;
|
||||||
|
import org.jclouds.sshj.config.SshjSshClientModule;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.inject.Module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Live test for CloudStack {@link ImageExtension} implementation.
|
||||||
|
*
|
||||||
|
* @author Andrew Bayer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test(groups = "live", singleThreaded = true, testName = "CloudStackImageExtensionLiveTest")
|
||||||
|
public class CloudStackImageExtensionLiveTest extends BaseImageExtensionLiveTest {
|
||||||
|
|
||||||
|
public CloudStackImageExtensionLiveTest() {
|
||||||
|
provider = "cloudstack";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Module getSshModule() {
|
||||||
|
return new SshjSshClientModule();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
{ "createtemplateresponse" : {"id":"3dc6ce25-a6cf-4d60-a664-3499993b511b","jobid":"4e345230-8fcc-48a3-8a37-c5fe960df671"} }
|
|
@ -0,0 +1 @@
|
||||||
|
{ "createtemplateresponse" : {"id":"3dc6ce25-a6cf-4d60-a664-3499993b511b","jobid":"4e345230-8fcc-48a3-8a37-c5fe960df671"} }
|
|
@ -0,0 +1 @@
|
||||||
|
{ "listtemplatesresponse" : { "count":1 ,"template" : [ {"id":"3dc6ce25-a6cf-4d60-a664-3499993b511b","name":"temp-template-ignore","displaytext":"sometext","ispublic":false,"created":"2013-06-21T12:37:01-0700","isready":true,"passwordenabled":false,"format":"QCOW2","isfeatured":false,"crossZones":false,"ostypeid":"be820210-c741-4c36-9ba1-f38363bd37d5","ostypename":"CentOS 5.6 (32-bit)","account":"andrew","zoneid":"1","zonename":"San Jose 1","status":"Download Complete","size":26843545600,"templatetype":"USER","hypervisor":"KVM","domain":"ROOT","domainid":"41a4917b-7952-499d-ba7f-4c57464d3dc8","isextractable":false,"checksum":"6dd5d7f073ff951b033a8cadb877bde2","sourcetemplateid":"9d597afb-4d3d-4a69-bf45-f95b0d1ee160"} ] } }
|
|
@ -0,0 +1,2 @@
|
||||||
|
{ "listvirtualmachinesresponse" : { "count":1 ,"virtualmachine" : [
|
||||||
|
{"id":"3239ade9-fd25-405c-8eda-59f0313a3fb0","name":"apb-cent32-bld","displayname":"apb-cent32-bld","account":"andrew","domainid":"41a4917b-7952-499d-ba7f-4c57464d3dc8","domain":"ROOT","created":"2013-04-16T16:25:57-0700","state":"Stopped","haenable":false,"zoneid":"1","zonename":"San Jose 1","hostid":"0","templateid":"9d597afb-4d3d-4a69-bf45-f95b0d1ee160","templatename":"centos-6.2-x32-template","templatedisplaytext":"CentOS 6.2 x32 Template","passwordenabled":false,"serviceofferingid":"7cc4f8c3-7c56-4155-9916-9f42072ea712","serviceofferingname":"Tiny","cpunumber":1,"cpuspeed":1600,"memory":1024,"cpuused":"0.01%","networkkbsread":319420,"networkkbswrite":3,"guestosid":"45de18f1-87c6-4646-8099-95c61f2a300a","rootdeviceid":0,"rootdevicetype":"Filesystem","securitygroup":[{"id":"50288900-28eb-4d7f-9c33-e4c26e3b66d2","name":"default","description":"Default Security Group"}],"nic":[{"id":"fd65b6fd-2c3e-4c8a-a0bc-6a5db4e8007a","networkid":"0c82cd9f-ca64-4df4-9300-b33d81562403","netmask":"255.255.254.0","gateway":"10.20.92.3","ipaddress":"10.20.92.96","traffictype":"Guest","type":"Shared","isdefault":true,"macaddress":"06:ec:68:00:0f:04"}],"hypervisor":"KVM","instancename":"i-4-69942-VM"} ] } }
|
|
@ -0,0 +1,2 @@
|
||||||
|
{ "listvolumesresponse" : { "count":1 ,"volume" : [
|
||||||
|
{"id":"fe1ada16-57a0-40ae-b577-01a153690fb4","name":"ROOT-69942","zoneid":"1","zonename":"San Jose 1","type":"ROOT","deviceid":0,"virtualmachineid":"3239ade9-fd25-405c-8eda-59f0313a3fb0","vmname":"apb-cent32-bld","vmdisplayname":"apb-cent32-bld","vmstate":"Stopped","size":139264,"created":"2013-04-16T16:25:57-0700","state":"Ready","account":"andrew","domainid":"41a4917b-7952-499d-ba7f-4c57464d3dc8","domain":"ROOT","storagetype":"local","hypervisor":"KVM","storage":"c2422.halxg.cloudera.com","destroyed":false,"serviceofferingid":"7cc4f8c3-7c56-4155-9916-9f42072ea712","serviceofferingname":"Tiny","serviceofferingdisplaytext":"Tiny (1 core, 1GB RAM)","isextractable":false} ] } }
|
|
@ -0,0 +1 @@
|
||||||
|
{ "listvolumesresponse" : { "count":1 ,"volume" : [ {"id":"fe1ada16-57a0-40ae-b577-01a153690fb4","name":"ROOT-69942","zoneid":"7dbc4787-ec2f-498d-95f0-848c8c81e5da","zonename":"MTV-Zone1","type":"ROOT","deviceid":0,"virtualmachineid":"3239ade9-fd25-405c-8eda-59f0313a3fb0","vmname":"apb-cent32-bld","vmdisplayname":"apb-cent32-bld","vmstate":"Stopped","size":139264,"created":"2013-04-16T16:25:57-0700","state":"Ready","account":"andrew","domainid":"41a4917b-7952-499d-ba7f-4c57464d3dc8","domain":"ROOT","storagetype":"local","hypervisor":"KVM","storage":"c2422.halxg.cloudera.com","destroyed":false,"serviceofferingid":"7cc4f8c3-7c56-4155-9916-9f42072ea712","serviceofferingname":"Tiny","serviceofferingdisplaytext":"Tiny (1 core, 1GB RAM)","isextractable":false} ] } }
|
|
@ -0,0 +1,2 @@
|
||||||
|
{ "queryasyncjobresultresponse" :
|
||||||
|
{"accountid":"ee092437-d681-499e-b78b-f4e449128247","userid":"0c9608c8-188c-47df-a934-d66dc96b96e3","cmd":"com.cloud.api.commands.CreateTemplateCmd","jobstatus":1,"jobprocstatus":0,"jobresultcode":0,"jobresulttype":"object","jobresult":{"template":{"id":"3dc6ce25-a6cf-4d60-a664-3499993b511b","name":"temp-template-ignore","displaytext":"temp-template-ignore","ispublic":false,"created":"2013-06-21T12:37:01-0700","isready":true,"passwordenabled":false,"format":"QCOW2","isfeatured":false,"crossZones":false,"ostypeid":"be820210-c741-4c36-9ba1-f38363bd37d5","ostypename":"CentOS 5.6 (32-bit)","account":"andrew","zoneid":"1","zonename":"San Jose 1","status":"Download Complete","size":26843545600,"templatetype":"USER","hypervisor":"KVM","domain":"ROOT","domainid":"41a4917b-7952-499d-ba7f-4c57464d3dc8","isextractable":false,"checksum":"6dd5d7f073ff951b033a8cadb877bde2","sourcetemplateid":"9d597afb-4d3d-4a69-bf45-f95b0d1ee160"}},"created":"2013-06-21T12:31:33-0700","jobid":"4e345230-8fcc-48a3-8a37-c5fe960df671"} }
|
|
@ -0,0 +1,2 @@
|
||||||
|
{ "queryasyncjobresultresponse" :
|
||||||
|
{"accountid":"ee092437-d681-499e-b78b-f4e449128247","userid":"0c9608c8-188c-47df-a934-d66dc96b96e3","cmd":"com.cloud.api.commands.StopVMCmd","jobstatus":1,"jobprocstatus":0,"jobresultcode":0,"jobresulttype":"object","jobresult":{"virtualmachine":{"id":"3239ade9-fd25-405c-8eda-59f0313a3fb0","name":"apb-cent32-bld","displayname":"apb-cent32-bld","account":"andrew","domainid":"41a4917b-7952-499d-ba7f-4c57464d3dc8","domain":"ROOT","created":"2013-04-16T16:25:57-0700","state":"Stopped","haenable":false,"zoneid":"1","zonename":"San Jose 1","hostid":"0","templateid":"9d597afb-4d3d-4a69-bf45-f95b0d1ee160","templatename":"centos-6.2-x32-template","templatedisplaytext":"CentOS 6.2 x32 Template","passwordenabled":false,"serviceofferingid":"7cc4f8c3-7c56-4155-9916-9f42072ea712","serviceofferingname":"Tiny","cpunumber":1,"cpuspeed":1600,"memory":1024,"cpuused":"-65.18%","networkkbsread":319420,"networkkbswrite":3,"guestosid":"45de18f1-87c6-4646-8099-95c61f2a300a","rootdeviceid":0,"rootdevicetype":"Filesystem","securitygroup":[{"id":"50288900-28eb-4d7f-9c33-e4c26e3b66d2","name":"default","description":"Default Security Group"}],"nic":[{"id":"fd65b6fd-2c3e-4c8a-a0bc-6a5db4e8007a","networkid":"0c82cd9f-ca64-4df4-9300-b33d81562403","netmask":"255.255.254.0","gateway":"10.20.92.3","ipaddress":"10.20.92.96","traffictype":"Guest","type":"Shared","isdefault":true,"macaddress":"06:ec:68:00:0f:04"}],"hypervisor":"KVM","instancename":"i-4-69942-VM"}},"created":"2013-06-21T12:49:59-0700","jobid":"a7d5127b-24a2-4a44-a4a7-25a6d057b453"} }
|
|
@ -0,0 +1 @@
|
||||||
|
{ "stopvirtualmachineresponse" : {"jobid":"a7d5127b-24a2-4a44-a4a7-25a6d057b453"} }
|
Loading…
Reference in New Issue