Issue 280: added captureVApp, but live test doesn't work yet

This commit is contained in:
Adrian Cole 2010-09-12 21:16:34 -07:00
parent 60bd5ede4f
commit d276b70162
8 changed files with 378 additions and 0 deletions

View File

@ -54,6 +54,7 @@ import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.XMLResponseParser; import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import org.jclouds.vcloud.binders.BindCaptureVAppParamsToXmlPayload;
import org.jclouds.vcloud.binders.BindCloneVAppParamsToXmlPayload; import org.jclouds.vcloud.binders.BindCloneVAppParamsToXmlPayload;
import org.jclouds.vcloud.binders.BindDeployVAppParamsToXmlPayload; import org.jclouds.vcloud.binders.BindDeployVAppParamsToXmlPayload;
import org.jclouds.vcloud.binders.BindGuestCustomizationSectionToXmlPayload; 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.filters.SetVCloudTokenCookie;
import org.jclouds.vcloud.functions.OrgNameCatalogNameVAppTemplateNameToEndpoint; import org.jclouds.vcloud.functions.OrgNameCatalogNameVAppTemplateNameToEndpoint;
import org.jclouds.vcloud.functions.OrgNameVDCNameResourceEntityNameToEndpoint; import org.jclouds.vcloud.functions.OrgNameVDCNameResourceEntityNameToEndpoint;
import org.jclouds.vcloud.options.CaptureVAppOptions;
import org.jclouds.vcloud.options.CloneVAppOptions; import org.jclouds.vcloud.options.CloneVAppOptions;
import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
import org.jclouds.vcloud.xml.OrgListHandler; import org.jclouds.vcloud.xml.OrgListHandler;
@ -172,6 +174,20 @@ public interface VCloudAsyncClient extends CommonVCloudAsyncClient {
@MapPayloadParam("newName") @ParamValidators(DnsNameValidator.class) String newName, @MapPayloadParam("newName") @ParamValidators(DnsNameValidator.class) String newName,
CloneVAppOptions... options); 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 * @see VCloudClient#findVAppInOrgVDCNamed
*/ */

View File

@ -35,6 +35,7 @@ import org.jclouds.vcloud.domain.VApp;
import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.domain.VAppTemplate;
import org.jclouds.vcloud.domain.Vm; import org.jclouds.vcloud.domain.Vm;
import org.jclouds.vcloud.domain.ovf.OvfEnvelope; import org.jclouds.vcloud.domain.ovf.OvfEnvelope;
import org.jclouds.vcloud.options.CaptureVAppOptions;
import org.jclouds.vcloud.options.CloneVAppOptions; import org.jclouds.vcloud.options.CloneVAppOptions;
import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; 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); 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); VAppTemplate getVAppTemplate(URI vAppTemplate);
OvfEnvelope getOvfEnvelopeForVAppTemplate(URI vAppTemplate); OvfEnvelope getOvfEnvelopeForVAppTemplate(URI vAppTemplate);

View File

@ -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");
}
}

View File

@ -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);
}
}
}

View File

@ -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());
}
}
}

View File

@ -65,6 +65,7 @@ import org.jclouds.vcloud.domain.internal.VDCImpl;
import org.jclouds.vcloud.domain.network.FenceMode; import org.jclouds.vcloud.domain.network.FenceMode;
import org.jclouds.vcloud.domain.network.NetworkConfig; import org.jclouds.vcloud.domain.network.NetworkConfig;
import org.jclouds.vcloud.filters.SetVCloudTokenCookie; import org.jclouds.vcloud.filters.SetVCloudTokenCookie;
import org.jclouds.vcloud.options.CaptureVAppOptions;
import org.jclouds.vcloud.options.CloneVAppOptions; import org.jclouds.vcloud.options.CloneVAppOptions;
import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
import org.jclouds.vcloud.xml.CatalogHandler; import org.jclouds.vcloud.xml.CatalogHandler;
@ -215,6 +216,50 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
checkFilters(request); 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 { public void testlistOrgs() throws SecurityException, NoSuchMethodException, IOException {
Method method = VCloudAsyncClient.class.getMethod("listOrgs"); Method method = VCloudAsyncClient.class.getMethod("listOrgs");
HttpRequest request = processor.createRequest(method); HttpRequest request = processor.createRequest(method);

View File

@ -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>

View File

@ -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>