add item to vcloud catalog

This commit is contained in:
Adrian Cole 2011-05-27 00:39:07 -06:00
parent da11370139
commit 85c0ca3fcf
6 changed files with 305 additions and 1 deletions

View File

@ -18,6 +18,7 @@
*/ */
package org.jclouds.vcloud; package org.jclouds.vcloud;
import static org.jclouds.vcloud.VCloudMediaType.CATALOGITEM_XML;
import static org.jclouds.vcloud.VCloudMediaType.DEPLOYVAPPPARAMS_XML; import static org.jclouds.vcloud.VCloudMediaType.DEPLOYVAPPPARAMS_XML;
import static org.jclouds.vcloud.VCloudMediaType.GUESTCUSTOMIZATIONSECTION_XML; import static org.jclouds.vcloud.VCloudMediaType.GUESTCUSTOMIZATIONSECTION_XML;
import static org.jclouds.vcloud.VCloudMediaType.NETWORKCONNECTIONSECTION_XML; import static org.jclouds.vcloud.VCloudMediaType.NETWORKCONNECTIONSECTION_XML;
@ -59,6 +60,7 @@ import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import org.jclouds.vcloud.binders.BindCPUCountToXmlPayload; import org.jclouds.vcloud.binders.BindCPUCountToXmlPayload;
import org.jclouds.vcloud.binders.BindCaptureVAppParamsToXmlPayload; import org.jclouds.vcloud.binders.BindCaptureVAppParamsToXmlPayload;
import org.jclouds.vcloud.binders.BindCatalogItemToXmlPayload;
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;
@ -66,6 +68,7 @@ import org.jclouds.vcloud.binders.BindInstantiateVAppTemplateParamsToXmlPayload;
import org.jclouds.vcloud.binders.BindMemoryToXmlPayload; import org.jclouds.vcloud.binders.BindMemoryToXmlPayload;
import org.jclouds.vcloud.binders.BindNetworkConnectionSectionToXmlPayload; import org.jclouds.vcloud.binders.BindNetworkConnectionSectionToXmlPayload;
import org.jclouds.vcloud.binders.BindUndeployVAppParamsToXmlPayload; import org.jclouds.vcloud.binders.BindUndeployVAppParamsToXmlPayload;
import org.jclouds.vcloud.domain.CatalogItem;
import org.jclouds.vcloud.domain.GuestCustomizationSection; import org.jclouds.vcloud.domain.GuestCustomizationSection;
import org.jclouds.vcloud.domain.NetworkConnectionSection; import org.jclouds.vcloud.domain.NetworkConnectionSection;
import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.ReferenceType;
@ -80,6 +83,7 @@ import org.jclouds.vcloud.functions.OrgNameVDCNameResourceEntityNameToEndpoint;
import org.jclouds.vcloud.options.CaptureVAppOptions; 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.CatalogItemHandler;
import org.jclouds.vcloud.xml.OrgListHandler; import org.jclouds.vcloud.xml.OrgListHandler;
import org.jclouds.vcloud.xml.TaskHandler; import org.jclouds.vcloud.xml.TaskHandler;
import org.jclouds.vcloud.xml.VAppHandler; import org.jclouds.vcloud.xml.VAppHandler;
@ -177,6 +181,33 @@ public interface VCloudAsyncClient extends CommonVCloudAsyncClient {
ListenableFuture<? extends Task> cloneVAppInVDC(@EndpointParam URI vdc, @PayloadParam("vApp") URI toClone, ListenableFuture<? extends Task> cloneVAppInVDC(@EndpointParam URI vdc, @PayloadParam("vApp") URI toClone,
@PayloadParam("newName") @ParamValidators(DnsNameValidator.class) String newName, CloneVAppOptions... options); @PayloadParam("newName") @ParamValidators(DnsNameValidator.class) String newName, CloneVAppOptions... options);
/**
* @see VCloudClient#addResourceEntitytoCatalog(URI, String, String, URI)
*/
@POST
@Path("/catalogItems")
@Consumes(CATALOGITEM_XML)
@Produces(CATALOGITEM_XML)
@MapBinder(BindCatalogItemToXmlPayload.class)
@XMLResponseParser(CatalogItemHandler.class)
ListenableFuture<? extends CatalogItem> addResourceEntitytoCatalog(@EndpointParam URI catalog,
@PayloadParam("name") String name, @PayloadParam("description") String description,
@PayloadParam("entity") URI entity);
/**
* @see VCloudClient#addResourceEntitytoCatalog(URI, String, String, URI,
* Map)
*/
@POST
@Path("/catalogItems")
@Consumes(CATALOGITEM_XML)
@Produces(CATALOGITEM_XML)
@MapBinder(BindCatalogItemToXmlPayload.class)
@XMLResponseParser(CatalogItemHandler.class)
ListenableFuture<? extends CatalogItem> addResourceEntitytoCatalog(@EndpointParam URI catalog,
@PayloadParam("name") String name, @PayloadParam("description") String description,
@PayloadParam("entity") URI entity, Map<String, String> properties);
/** /**
* @see VCloudClient#captureVAppInVDC * @see VCloudClient#captureVAppInVDC
*/ */

View File

@ -28,6 +28,7 @@ import javax.annotation.Nullable;
import org.jclouds.concurrent.Timeout; import org.jclouds.concurrent.Timeout;
import org.jclouds.ovf.Envelope; import org.jclouds.ovf.Envelope;
import org.jclouds.vcloud.domain.CatalogItem;
import org.jclouds.vcloud.domain.GuestCustomizationSection; import org.jclouds.vcloud.domain.GuestCustomizationSection;
import org.jclouds.vcloud.domain.NetworkConnectionSection; import org.jclouds.vcloud.domain.NetworkConnectionSection;
import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.ReferenceType;
@ -286,4 +287,26 @@ public interface VCloudClient extends CommonVCloudClient {
@Deprecated @Deprecated
Task deleteVApp(URI vAppId); Task deleteVApp(URI vAppId);
/**
* A catalog can contain references to vApp templates and media images that
* have been uploaded to any vDC in an organization. A vApp template or media
* image can be listed in at most one catalog.
*
* @param catalog
* URI of the catalog to add the resourceEntity from
* @param name
* name of the entry in the catalog
* @param description
* description of the entry in the catalog
* @param entity
* the reference to the item from the VDC
* @param properties
* metadata to associate with this item
* @return the new catalog item
*/
CatalogItem addResourceEntitytoCatalog(URI catalog, String name, String description, URI entity,
Map<String, String> properties);
CatalogItem addResourceEntitytoCatalog(URI catalog, String name, String description, URI entity);
} }

View File

@ -0,0 +1,130 @@
/**
*
* Copyright (C) 2011 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.net.URI;
import java.util.Map;
import java.util.Map.Entry;
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 com.google.common.collect.ImmutableMap;
import com.google.inject.Inject;
import com.jamesmurty.utils.XMLBuilder;
/**
*
* @author Adrian Cole
*
*/
@Singleton
public class BindCatalogItemToXmlPayload implements MapBinder {
protected final String ns;
protected final String schema;
private final BindToStringPayload stringBinder;
@Inject
public BindCatalogItemToXmlPayload(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;
}
@Override
public <R extends HttpRequest> R bindToRequest(R 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 name = checkNotNull(postParams.get("name"), "name");
String description = checkNotNull(postParams.get("description"), "description");
URI entity = URI.create(checkNotNull(postParams.get("entity"), "entity"));
Map<String, String> properties = findMapInArgsOrNull(gRequest);
if (properties == null) {
properties = ImmutableMap.of();
}
try {
return stringBinder.bindToRequest(request, generateXml(name, description, entity, properties));
} 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 description, URI entity, Map<String, String> properties)
throws ParserConfigurationException, FactoryConfigurationError, TransformerException {
XMLBuilder rootBuilder = buildRoot(templateName);
rootBuilder.e("Description").t(description);
rootBuilder.e("Entity").a("href", entity.toASCIIString());
for (Entry<String, String> entry : properties.entrySet()) {
rootBuilder.e("Property").a("key", entry.getKey()).t(entry.getValue());
}
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("CatalogItem").a("name", name).a("xmlns", ns)
.a("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance").a("xsi:schemaLocation", ns + " " + schema);
return rootBuilder;
}
@SuppressWarnings("unchecked")
protected Map<String, String> findMapInArgsOrNull(GeneratedHttpRequest<?> gRequest) {
for (Object arg : gRequest.getArgs()) {
if (arg instanceof Map) {
return (Map<String, String>) arg;
}
}
return null;
}
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
throw new IllegalStateException("CatalogItem is needs parameters");
}
protected String ifNullDefaultTo(String value, String defaultValue) {
return value != null ? value : checkNotNull(defaultValue, "defaultValue");
}
}

View File

@ -80,7 +80,7 @@ public class VCloudDestroyNodeStrategy implements DestroyNodeStrategy {
void deleteVApp(URI vappId) { void deleteVApp(URI vappId) {
logger.debug(">> deleting vApp(%s)", vappId); logger.debug(">> deleting vApp(%s)", vappId);
Task task = client.deleteVApp(vappId); Task task = client.deleteVAppTemplateVAppOrMediaImage(vappId);
if (!successTester.apply(task.getHref())) { if (!successTester.apply(task.getHref())) {
throw new RuntimeException(String.format("failed to %s %s: %s", "delete", vappId, task)); throw new RuntimeException(String.format("failed to %s %s: %s", "delete", vappId, task));
} }

View File

@ -762,6 +762,50 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
checkFilters(request); checkFilters(request);
} }
public void testAddResourceEntitytoCatalogProperties() throws SecurityException, NoSuchMethodException, IOException {
Method method = VCloudAsyncClient.class.getMethod("addResourceEntitytoCatalog", URI.class, String.class,
String.class, URI.class, Map.class);
HttpRequest request = processor.createRequest(method,
URI.create("https://vcenterprise.bluelock.com/api/v1.0/catalog/1"), "myname", "mydescription",
URI.create("http://fooentity"), ImmutableMap.of("foo", "bar"));
assertRequestLineEquals(request,
"POST https://vcenterprise.bluelock.com/api/v1.0/catalog/1/catalogItems HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Accept: application/vnd.vmware.vcloud.catalogItem+xml\n");
assertPayloadEquals(
request,
"<CatalogItem xmlns=\"http://www.vmware.com/vcloud/v1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"myname\" xsi:schemaLocation=\"http://www.vmware.com/vcloud/v1 http://vcloud.safesecureweb.com/ns/vcloud.xsd\"><Description>mydescription</Description><Entity href=\"http://fooentity\"/><Property key=\"foo\">bar</Property></CatalogItem>",
"application/vnd.vmware.vcloud.catalogItem+xml", false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, CatalogItemHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
public void testAddResourceEntitytoCatalog() throws SecurityException, NoSuchMethodException, IOException {
Method method = VCloudAsyncClient.class.getMethod("addResourceEntitytoCatalog", URI.class, String.class,
String.class, URI.class);
HttpRequest request = processor.createRequest(method,
URI.create("https://vcenterprise.bluelock.com/api/v1.0/catalog/1"), "myname", "mydescription",
URI.create("http://fooentity"));
assertRequestLineEquals(request,
"POST https://vcenterprise.bluelock.com/api/v1.0/catalog/1/catalogItems HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Accept: application/vnd.vmware.vcloud.catalogItem+xml\n");
assertPayloadEquals(
request,
"<CatalogItem xmlns=\"http://www.vmware.com/vcloud/v1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"myname\" xsi:schemaLocation=\"http://www.vmware.com/vcloud/v1 http://vcloud.safesecureweb.com/ns/vcloud.xsd\"><Description>mydescription</Description><Entity href=\"http://fooentity\"/></CatalogItem>",
"application/vnd.vmware.vcloud.catalogItem+xml", false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, CatalogItemHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
public void testPowerOffVAppOrVm() throws SecurityException, NoSuchMethodException, IOException { public void testPowerOffVAppOrVm() throws SecurityException, NoSuchMethodException, IOException {
Method method = VCloudAsyncClient.class.getMethod("powerOffVAppOrVm", URI.class); Method method = VCloudAsyncClient.class.getMethod("powerOffVAppOrVm", URI.class);
HttpRequest request = processor.createRequest(method, HttpRequest request = processor.createRequest(method,

View File

@ -0,0 +1,76 @@
/**
*
* Copyright (C) 2011 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.checkNotNull;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.Properties;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.vcloud.VCloudPropertiesBuilder;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.name.Names;
/**
* Tests behavior of {@code BindCatalogItemToXmlPayload}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class BindCatalogItemToXmlPayloadTest {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
Properties props = new Properties();
Names.bindProperties(binder(), checkNotNull(new VCloudPropertiesBuilder(props).build(), "properties"));
}
});
public void testDefault() throws IOException {
String expected = "<CatalogItem xmlns=\"http://www.vmware.com/vcloud/v1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"myname\" xsi:schemaLocation=\"http://www.vmware.com/vcloud/v1 http://vcloud.safesecureweb.com/ns/vcloud.xsd\"><Description>mydescription</Description><Entity href=\"http://fooentity\"/><Property key=\"foo\">bar</Property></CatalogItem>";
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(ImmutableList.<Object> of(ImmutableMap.of("foo", "bar"))).anyTimes();
request.setPayload(expected);
replay(request);
BindCatalogItemToXmlPayload binder = injector.getInstance(BindCatalogItemToXmlPayload.class);
Map<String, String> map = ImmutableMap.of("name", "myname", "description", "mydescription", "entity",
"http://fooentity");
binder.bindToRequest(request, map);
verify(request);
}
}