mirror of https://github.com/apache/jclouds.git
Issue 280: added captureVApp, but live test doesn't work yet
This commit is contained in:
parent
60bd5ede4f
commit
d276b70162
|
@ -54,6 +54,7 @@ import org.jclouds.rest.annotations.RequestFilters;
|
|||
import org.jclouds.rest.annotations.XMLResponseParser;
|
||||
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
|
||||
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
|
||||
import org.jclouds.vcloud.binders.BindCaptureVAppParamsToXmlPayload;
|
||||
import org.jclouds.vcloud.binders.BindCloneVAppParamsToXmlPayload;
|
||||
import org.jclouds.vcloud.binders.BindDeployVAppParamsToXmlPayload;
|
||||
import org.jclouds.vcloud.binders.BindGuestCustomizationSectionToXmlPayload;
|
||||
|
@ -70,6 +71,7 @@ import org.jclouds.vcloud.endpoints.OrgList;
|
|||
import org.jclouds.vcloud.filters.SetVCloudTokenCookie;
|
||||
import org.jclouds.vcloud.functions.OrgNameCatalogNameVAppTemplateNameToEndpoint;
|
||||
import org.jclouds.vcloud.functions.OrgNameVDCNameResourceEntityNameToEndpoint;
|
||||
import org.jclouds.vcloud.options.CaptureVAppOptions;
|
||||
import org.jclouds.vcloud.options.CloneVAppOptions;
|
||||
import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
|
||||
import org.jclouds.vcloud.xml.OrgListHandler;
|
||||
|
@ -172,6 +174,20 @@ public interface VCloudAsyncClient extends CommonVCloudAsyncClient {
|
|||
@MapPayloadParam("newName") @ParamValidators(DnsNameValidator.class) String newName,
|
||||
CloneVAppOptions... options);
|
||||
|
||||
/**
|
||||
* @see VCloudClient#captureVAppInVDC
|
||||
*/
|
||||
@POST
|
||||
@Path("/action/captureVApp")
|
||||
@Produces("application/vnd.vmware.vcloud.captureVAppParams+xml")
|
||||
@Consumes(VAPPTEMPLATE_XML)
|
||||
@XMLResponseParser(VAppTemplateHandler.class)
|
||||
@MapBinder(BindCaptureVAppParamsToXmlPayload.class)
|
||||
ListenableFuture<? extends VAppTemplate> captureVAppInVDC(@EndpointParam URI vdc,
|
||||
@MapPayloadParam("vApp") URI toCapture,
|
||||
@MapPayloadParam("templateName") @ParamValidators(DnsNameValidator.class) String templateName,
|
||||
CaptureVAppOptions... options);
|
||||
|
||||
/**
|
||||
* @see VCloudClient#findVAppInOrgVDCNamed
|
||||
*/
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.jclouds.vcloud.domain.VApp;
|
|||
import org.jclouds.vcloud.domain.VAppTemplate;
|
||||
import org.jclouds.vcloud.domain.Vm;
|
||||
import org.jclouds.vcloud.domain.ovf.OvfEnvelope;
|
||||
import org.jclouds.vcloud.options.CaptureVAppOptions;
|
||||
import org.jclouds.vcloud.options.CloneVAppOptions;
|
||||
import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
|
||||
|
||||
|
@ -67,6 +68,20 @@ public interface VCloudClient extends CommonVCloudClient {
|
|||
|
||||
Task cloneVAppInVDC(URI vDC, URI toClone, String newName, CloneVAppOptions... options);
|
||||
|
||||
|
||||
/**
|
||||
* The captureVApp request creates a vApp template from an instantiated vApp.
|
||||
* <h4>Note</h4>
|
||||
* Before it can be captured, a vApp must be undeployed
|
||||
*
|
||||
* @param vDC
|
||||
* @param toClone
|
||||
* @param templateName
|
||||
* @param options
|
||||
* @return template in progress
|
||||
*/
|
||||
VAppTemplate captureVAppInVDC(URI vDC, URI toClone, String templateName, CaptureVAppOptions... options);
|
||||
|
||||
VAppTemplate getVAppTemplate(URI vAppTemplate);
|
||||
|
||||
OvfEnvelope getOvfEnvelopeForVAppTemplate(URI vAppTemplate);
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
package org.jclouds.vcloud.binders;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE;
|
||||
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javax.xml.parsers.FactoryConfigurationError;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.MapBinder;
|
||||
import org.jclouds.rest.binders.BindToStringPayload;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.vcloud.VCloudExpressMediaType;
|
||||
import org.jclouds.vcloud.options.CaptureVAppOptions;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.jamesmurty.utils.XMLBuilder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
@Singleton
|
||||
public class BindCaptureVAppParamsToXmlPayload implements MapBinder {
|
||||
|
||||
protected final String ns;
|
||||
protected final String schema;
|
||||
private final BindToStringPayload stringBinder;
|
||||
|
||||
@Inject
|
||||
public BindCaptureVAppParamsToXmlPayload(BindToStringPayload stringBinder,
|
||||
@Named(PROPERTY_VCLOUD_XML_NAMESPACE) String ns, @Named(PROPERTY_VCLOUD_XML_SCHEMA) String schema) {
|
||||
this.ns = ns;
|
||||
this.schema = schema;
|
||||
this.stringBinder = stringBinder;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void bindToRequest(HttpRequest request, Map<String, String> postParams) {
|
||||
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
|
||||
"this binder is only valid for GeneratedHttpRequests!");
|
||||
GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
|
||||
checkState(gRequest.getArgs() != null, "args should be initialized at this point");
|
||||
String templateName = checkNotNull(postParams.remove("templateName"), "templateName");
|
||||
String vApp = checkNotNull(postParams.remove("vApp"), "vApp");
|
||||
|
||||
CaptureVAppOptions options = findOptionsInArgsOrNull(gRequest);
|
||||
if (options == null) {
|
||||
options = new CaptureVAppOptions();
|
||||
}
|
||||
try {
|
||||
stringBinder.bindToRequest(request, generateXml(templateName, vApp, options));
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (FactoryConfigurationError e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (TransformerException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected String generateXml(String templateName, String vApp, CaptureVAppOptions options)
|
||||
throws ParserConfigurationException, FactoryConfigurationError, TransformerException {
|
||||
XMLBuilder rootBuilder = buildRoot(templateName);
|
||||
if (options.getDescription() != null)
|
||||
rootBuilder.e("Description").text(options.getDescription());
|
||||
rootBuilder.e("Source").a("href", vApp).a("type", VCloudExpressMediaType.VAPP_XML);
|
||||
Properties outputProperties = new Properties();
|
||||
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
|
||||
return rootBuilder.asString(outputProperties);
|
||||
}
|
||||
|
||||
protected XMLBuilder buildRoot(String name) throws ParserConfigurationException, FactoryConfigurationError {
|
||||
XMLBuilder rootBuilder = XMLBuilder.create("CaptureVAppParams").a("name", name).a("xmlns", ns).a("xmlns:xsi",
|
||||
"http://www.w3.org/2001/XMLSchema-instance").a("xsi:schemaLocation", ns + " " + schema);
|
||||
return rootBuilder;
|
||||
}
|
||||
|
||||
protected CaptureVAppOptions findOptionsInArgsOrNull(GeneratedHttpRequest<?> gRequest) {
|
||||
for (Object arg : gRequest.getArgs()) {
|
||||
if (arg instanceof CaptureVAppOptions) {
|
||||
return (CaptureVAppOptions) arg;
|
||||
} else if (arg instanceof CaptureVAppOptions[]) {
|
||||
CaptureVAppOptions[] options = (CaptureVAppOptions[]) arg;
|
||||
return (options.length > 0) ? options[0] : null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void bindToRequest(HttpRequest request, Object input) {
|
||||
throw new IllegalStateException("CaptureVAppParams is needs parameters");
|
||||
}
|
||||
|
||||
protected String ifNullDefaultTo(String value, String defaultValue) {
|
||||
return value != null ? value : checkNotNull(defaultValue, "defaultValue");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
package org.jclouds.vcloud.options;
|
||||
|
||||
import static com.google.common.base.Preconditions.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
public class CaptureVAppOptions {
|
||||
|
||||
private String description;
|
||||
|
||||
public CaptureVAppOptions withDescription(String description) {
|
||||
checkNotNull(description, "description");
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
/**
|
||||
* @see CaptureVAppOptions#withDescription(String)
|
||||
*/
|
||||
public static CaptureVAppOptions withDescription(String description) {
|
||||
CaptureVAppOptions options = new CaptureVAppOptions();
|
||||
return options.withDescription(description);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
package org.jclouds.vcloud;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.compute.ComputeService;
|
||||
import org.jclouds.compute.ComputeServiceContextFactory;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
||||
import org.jclouds.predicates.RetryablePredicate;
|
||||
import org.jclouds.vcloud.domain.Task;
|
||||
import org.jclouds.vcloud.domain.VAppTemplate;
|
||||
import org.jclouds.vcloud.predicates.TaskSuccess;
|
||||
import org.testng.annotations.BeforeGroups;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Module;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "live", enabled = true, sequential = true, testName = "vcloud.CaptureVAppLiveTest")
|
||||
public class CaptureVAppLiveTest {
|
||||
|
||||
protected String identity;
|
||||
protected String provider;
|
||||
protected String credential;
|
||||
protected ComputeService client;
|
||||
protected String tag = System.getProperty("user.name") + "cap";
|
||||
|
||||
protected void setupCredentials() {
|
||||
provider = "vcloud";
|
||||
identity = checkNotNull(System.getProperty("vcloud.identity"), "vcloud.identity");
|
||||
credential = checkNotNull(System.getProperty("vcloud.credential"), "vcloud.credential");
|
||||
}
|
||||
|
||||
@BeforeGroups(groups = { "live" })
|
||||
public void setupClient() {
|
||||
setupCredentials();
|
||||
Properties props = new Properties();
|
||||
props.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "true");
|
||||
props.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, "true");
|
||||
client = new ComputeServiceContextFactory().createContext(provider, identity, credential,
|
||||
ImmutableSet.<Module> of(new Log4JLoggingModule()), props).getComputeService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCaptureVApp() throws Exception {
|
||||
|
||||
NodeMetadata node = null;
|
||||
VAppTemplate vappTemplate = null;
|
||||
try {
|
||||
|
||||
node = getOnlyElement(client.runNodesWithTag(tag, 1));
|
||||
|
||||
VCloudClient vcloudApi = VCloudClient.class.cast(client.getContext().getProviderSpecificContext().getApi());
|
||||
|
||||
Predicate<URI> taskTester = new RetryablePredicate<URI>(new TaskSuccess(vcloudApi), 600, 5, TimeUnit.SECONDS);
|
||||
|
||||
// I have to powerOff first
|
||||
Task task = vcloudApi.powerOffVAppOrVm(URI.create(node.getId()));
|
||||
|
||||
// wait up to ten minutes per above
|
||||
assert taskTester.apply(task.getHref()) : node;
|
||||
|
||||
// having a problem where the api is returning an error telling us to stop!
|
||||
|
||||
// // I have to undeploy first
|
||||
// task = vcloudApi.undeployVAppOrVm(URI.create(node.getId()));
|
||||
//
|
||||
// // wait up to ten minutes per above
|
||||
// assert taskTester.apply(task.getHref()) : node;
|
||||
|
||||
// vdc is equiv to the node's location
|
||||
// vapp uri is the same as the node's id
|
||||
vappTemplate = vcloudApi.captureVAppInVDC(URI.create(node.getLocation().getId()), URI.create(node.getId()),
|
||||
tag);
|
||||
|
||||
task = vappTemplate.getTasks().get(0);
|
||||
|
||||
// wait up to ten minutes per above
|
||||
assert taskTester.apply(task.getHref()) : vappTemplate;
|
||||
|
||||
// TODO implement delete vAppTemplate
|
||||
} finally {
|
||||
if (node != null)
|
||||
client.destroyNode(node.getId());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -65,6 +65,7 @@ import org.jclouds.vcloud.domain.internal.VDCImpl;
|
|||
import org.jclouds.vcloud.domain.network.FenceMode;
|
||||
import org.jclouds.vcloud.domain.network.NetworkConfig;
|
||||
import org.jclouds.vcloud.filters.SetVCloudTokenCookie;
|
||||
import org.jclouds.vcloud.options.CaptureVAppOptions;
|
||||
import org.jclouds.vcloud.options.CloneVAppOptions;
|
||||
import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
|
||||
import org.jclouds.vcloud.xml.CatalogHandler;
|
||||
|
@ -215,6 +216,50 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
|
|||
checkFilters(request);
|
||||
}
|
||||
|
||||
|
||||
public void testCaptureVAppInVDC() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = VCloudAsyncClient.class.getMethod("captureVAppInVDC", URI.class, URI.class, String.class,
|
||||
CaptureVAppOptions[].class);
|
||||
HttpRequest request = processor.createRequest(method, URI
|
||||
.create("https://vcenterprise.bluelock.com/api/v1.0/vdc/1"), URI
|
||||
.create("https://vcenterprise.bluelock.com/api/v1.0/vapp/4181"), "my-template");
|
||||
|
||||
assertRequestLineEquals(request,
|
||||
"POST https://vcenterprise.bluelock.com/api/v1.0/vdc/1/action/captureVApp HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(request, "Accept: application/vnd.vmware.vcloud.vAppTemplate+xml\n");
|
||||
assertPayloadEquals(request, Utils.toStringAndClose(getClass().getResourceAsStream("/captureVApp-default.xml")),
|
||||
"application/vnd.vmware.vcloud.captureVAppParams+xml", false);
|
||||
|
||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, VAppTemplateHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
|
||||
checkFilters(request);
|
||||
}
|
||||
|
||||
public void testCaptureVAppInVDCOptions() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = VCloudAsyncClient.class.getMethod("captureVAppInVDC", URI.class, URI.class, String.class,
|
||||
CaptureVAppOptions[].class);
|
||||
HttpRequest request = processor.createRequest(method, URI
|
||||
.create("https://vcenterprise.bluelock.com/api/v1.0/vdc/1"), URI
|
||||
.create("https://vcenterprise.bluelock.com/api/v1.0/vapp/201"), "my-template",
|
||||
new CaptureVAppOptions().withDescription("The description of the new vApp Template"));
|
||||
|
||||
assertRequestLineEquals(request,
|
||||
"POST https://vcenterprise.bluelock.com/api/v1.0/vdc/1/action/captureVApp HTTP/1.1");
|
||||
assertNonPayloadHeadersEqual(request, "Accept: application/vnd.vmware.vcloud.vAppTemplate+xml\n");
|
||||
assertPayloadEquals(request, Utils.toStringAndClose(getClass().getResourceAsStream("/captureVApp.xml")),
|
||||
"application/vnd.vmware.vcloud.captureVAppParams+xml", false);
|
||||
|
||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
||||
assertSaxResponseParserClassEquals(method, VAppTemplateHandler.class);
|
||||
assertExceptionParserClassEquals(method, null);
|
||||
|
||||
checkFilters(request);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void testlistOrgs() throws SecurityException, NoSuchMethodException, IOException {
|
||||
Method method = VCloudAsyncClient.class.getMethod("listOrgs");
|
||||
HttpRequest request = processor.createRequest(method);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<CaptureVAppParams xmlns="http://www.vmware.com/vcloud/v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="my-template" xsi:schemaLocation="http://www.vmware.com/vcloud/v1 http://vcloud.safesecureweb.com/ns/vcloud.xsd"><Source href="https://vcenterprise.bluelock.com/api/v1.0/vapp/4181" type="application/vnd.vmware.vcloud.vApp+xml"/></CaptureVAppParams>
|
|
@ -0,0 +1 @@
|
|||
<CaptureVAppParams xmlns="http://www.vmware.com/vcloud/v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="my-template" xsi:schemaLocation="http://www.vmware.com/vcloud/v1 http://vcloud.safesecureweb.com/ns/vcloud.xsd"><Description>The description of the new vApp Template</Description><Source href="https://vcenterprise.bluelock.com/api/v1.0/vapp/201" type="application/vnd.vmware.vcloud.vApp+xml"/></CaptureVAppParams>
|
Loading…
Reference in New Issue