From fb663fceeda4abce16da68de0110c54087bb0227 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 5 Mar 2011 16:55:59 -0500 Subject: [PATCH] Issue 498:[vcloud] expose IpAddressAllocationMode to compute service --- .../org/jclouds/vcloud/VCloudAsyncClient.java | 47 +++++--- .../java/org/jclouds/vcloud/VCloudClient.java | 27 +++-- ...dNetworkConnectionSectionToXmlPayload.java | 109 ++++++++++++++++++ .../options/VCloudTemplateOptions.java | 37 +++++- ...IntoNameThenCustomizeDeployAndPowerOn.java | 83 +++++++++---- .../vcloud/domain/NetworkConnection.java | 73 +++++++++++- .../domain/NetworkConnectionSection.java | 70 +++++++++-- ...workConnectionSectionToXmlPayloadTest.java | 86 ++++++++++++++ .../options/VCloudTemplateOptionsTest.java | 26 ++++- 9 files changed, 486 insertions(+), 72 deletions(-) create mode 100644 apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindNetworkConnectionSectionToXmlPayload.java create mode 100644 apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindNetworkConnectionSectionToXmlPayloadTest.java diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudAsyncClient.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudAsyncClient.java index 6813714173..9f34a339e2 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudAsyncClient.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudAsyncClient.java @@ -21,6 +21,7 @@ package org.jclouds.vcloud; import static org.jclouds.vcloud.VCloudMediaType.DEPLOYVAPPPARAMS_XML; import static org.jclouds.vcloud.VCloudMediaType.GUESTCUSTOMIZATIONSECTION_XML; +import static org.jclouds.vcloud.VCloudMediaType.NETWORKCONNECTIONSECTION_XML; import static org.jclouds.vcloud.VCloudMediaType.TASK_XML; import static org.jclouds.vcloud.VCloudMediaType.UNDEPLOYVAPPPARAMS_XML; import static org.jclouds.vcloud.VCloudMediaType.VAPPTEMPLATE_XML; @@ -47,9 +48,9 @@ import org.jclouds.rest.annotations.Endpoint; import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.ParamValidators; import org.jclouds.rest.annotations.PayloadParam; import org.jclouds.rest.annotations.PayloadParams; -import org.jclouds.rest.annotations.ParamValidators; import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.XMLResponseParser; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; @@ -59,8 +60,10 @@ import org.jclouds.vcloud.binders.BindCloneVAppParamsToXmlPayload; import org.jclouds.vcloud.binders.BindDeployVAppParamsToXmlPayload; import org.jclouds.vcloud.binders.BindGuestCustomizationSectionToXmlPayload; import org.jclouds.vcloud.binders.BindInstantiateVAppTemplateParamsToXmlPayload; +import org.jclouds.vcloud.binders.BindNetworkConnectionSectionToXmlPayload; import org.jclouds.vcloud.binders.BindUndeployVAppParamsToXmlPayload; import org.jclouds.vcloud.domain.GuestCustomizationSection; +import org.jclouds.vcloud.domain.NetworkConnectionSection; import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.VApp; @@ -140,9 +143,9 @@ public interface VCloudAsyncClient extends CommonVCloudAsyncClient { @XMLResponseParser(VAppTemplateHandler.class) @ExceptionParser(ReturnNullOnNotFoundOr404.class) ListenableFuture findVAppTemplateInOrgCatalogNamed( - @Nullable @EndpointParam(parser = OrgNameCatalogNameVAppTemplateNameToEndpoint.class) String orgName, - @Nullable @EndpointParam(parser = OrgNameCatalogNameVAppTemplateNameToEndpoint.class) String catalogName, - @EndpointParam(parser = OrgNameCatalogNameVAppTemplateNameToEndpoint.class) String itemName); + @Nullable @EndpointParam(parser = OrgNameCatalogNameVAppTemplateNameToEndpoint.class) String orgName, + @Nullable @EndpointParam(parser = OrgNameCatalogNameVAppTemplateNameToEndpoint.class) String catalogName, + @EndpointParam(parser = OrgNameCatalogNameVAppTemplateNameToEndpoint.class) String itemName); /** * @see VCloudClient#instantiateVAppTemplateInVDC @@ -154,9 +157,9 @@ public interface VCloudAsyncClient extends CommonVCloudAsyncClient { @XMLResponseParser(VAppHandler.class) @MapBinder(BindInstantiateVAppTemplateParamsToXmlPayload.class) ListenableFuture instantiateVAppTemplateInVDC(@EndpointParam URI vdc, - @PayloadParam("template") URI template, - @PayloadParam("name") @ParamValidators(DnsNameValidator.class) String appName, - InstantiateVAppTemplateOptions... options); + @PayloadParam("template") URI template, + @PayloadParam("name") @ParamValidators(DnsNameValidator.class) String appName, + InstantiateVAppTemplateOptions... options); /** * @see VCloudClient#cloneVAppInVDC @@ -168,8 +171,7 @@ public interface VCloudAsyncClient extends CommonVCloudAsyncClient { @XMLResponseParser(TaskHandler.class) @MapBinder(BindCloneVAppParamsToXmlPayload.class) ListenableFuture 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#captureVAppInVDC @@ -181,9 +183,9 @@ public interface VCloudAsyncClient extends CommonVCloudAsyncClient { @XMLResponseParser(VAppTemplateHandler.class) @MapBinder(BindCaptureVAppParamsToXmlPayload.class) ListenableFuture captureVAppInVDC(@EndpointParam URI vdc, - @PayloadParam("vApp") URI toCapture, - @PayloadParam("templateName") @ParamValidators(DnsNameValidator.class) String templateName, - CaptureVAppOptions... options); + @PayloadParam("vApp") URI toCapture, + @PayloadParam("templateName") @ParamValidators(DnsNameValidator.class) String templateName, + CaptureVAppOptions... options); /** * @see VCloudClient#findVAppInOrgVDCNamed @@ -193,9 +195,9 @@ public interface VCloudAsyncClient extends CommonVCloudAsyncClient { @XMLResponseParser(VAppHandler.class) @ExceptionParser(ReturnNullOnNotFoundOr404.class) ListenableFuture findVAppInOrgVDCNamed( - @Nullable @EndpointParam(parser = OrgNameVDCNameResourceEntityNameToEndpoint.class) String orgName, - @Nullable @EndpointParam(parser = OrgNameVDCNameResourceEntityNameToEndpoint.class) String catalogName, - @EndpointParam(parser = OrgNameVDCNameResourceEntityNameToEndpoint.class) String vAppName); + @Nullable @EndpointParam(parser = OrgNameVDCNameResourceEntityNameToEndpoint.class) String orgName, + @Nullable @EndpointParam(parser = OrgNameVDCNameResourceEntityNameToEndpoint.class) String catalogName, + @EndpointParam(parser = OrgNameVDCNameResourceEntityNameToEndpoint.class) String vAppName); /** * @see VCloudClient#getVApp @@ -224,8 +226,19 @@ public interface VCloudAsyncClient extends CommonVCloudAsyncClient { @Path("/guestCustomizationSection") @XMLResponseParser(TaskHandler.class) ListenableFuture updateGuestCustomizationOfVm( - @EndpointParam URI vm, - @BinderParam(BindGuestCustomizationSectionToXmlPayload.class) GuestCustomizationSection guestCustomizationSection); + @EndpointParam URI vm, + @BinderParam(BindGuestCustomizationSectionToXmlPayload.class) GuestCustomizationSection guestCustomizationSection); + + /** + * @see VCloudClient#updateNetworkConnectionOfVm + */ + @PUT + @Consumes(TASK_XML) + @Produces(NETWORKCONNECTIONSECTION_XML) + @Path("/networkConnectionSection") + @XMLResponseParser(TaskHandler.class) + ListenableFuture updateNetworkConnectionOfVm(@EndpointParam URI vm, + @BinderParam(BindNetworkConnectionSectionToXmlPayload.class) NetworkConnectionSection networkConnectionSection); /** * @see VCloudClient#deployVAppOrVm diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudClient.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudClient.java index 25fcfd2559..78bb784fa4 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudClient.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/VCloudClient.java @@ -29,6 +29,7 @@ import javax.annotation.Nullable; import org.jclouds.concurrent.Timeout; import org.jclouds.vcloud.domain.GuestCustomizationSection; +import org.jclouds.vcloud.domain.NetworkConnectionSection; import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.VApp; @@ -48,14 +49,15 @@ import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; */ @Timeout(duration = 300, timeUnit = TimeUnit.SECONDS) public interface VCloudClient extends CommonVCloudClient { - + /** * Get a Screen Thumbnail for a Virtual Machine * - * @param vm to snapshot + * @param vm + * to snapshot */ InputStream getThumbnailOfVm(URI vm); - + /** * The response to a login request includes a list of the organizations to which the * authenticated user has access. @@ -68,11 +70,9 @@ 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. - *

Note

- * Before it can be captured, a vApp must be undeployed + * The captureVApp request creates a vApp template from an instantiated vApp.

Note

+ * Before it can be captured, a vApp must be undeployed * * @param vDC * @param toClone @@ -97,6 +97,17 @@ public interface VCloudClient extends CommonVCloudClient { */ Task updateGuestCustomizationOfVm(URI vm, GuestCustomizationSection guestCustomizationSection); + /** + * Modify the Network Connection Section of a Virtual Machine + * + * @param vm + * uri to modify + * @param updated + * networkConnectionSection + * @return task in progress + */ + Task updateNetworkConnectionOfVm(URI vm, NetworkConnectionSection guestCustomizationSection); + /** * returns the vapp template corresponding to a catalog item in the catalog associated with the * specified name. Note that the org and catalog parameters can be null to choose default. @@ -112,7 +123,7 @@ public interface VCloudClient extends CommonVCloudClient { * if you specified an org, catalog, or catalog item name that isn't present */ VAppTemplate findVAppTemplateInOrgCatalogNamed(@Nullable String orgName, @Nullable String catalogName, - String itemName); + String itemName); VApp findVAppInOrgVDCNamed(@Nullable String orgName, @Nullable String catalogName, String vAppName); diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindNetworkConnectionSectionToXmlPayload.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindNetworkConnectionSectionToXmlPayload.java new file mode 100644 index 0000000000..0f84287976 --- /dev/null +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindNetworkConnectionSectionToXmlPayload.java @@ -0,0 +1,109 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE; +import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA; + +import java.util.Properties; + +import javax.annotation.Resource; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.http.HttpRequest; +import org.jclouds.logging.Logger; +import org.jclouds.rest.binders.BindToStringPayload; +import org.jclouds.vcloud.domain.NetworkConnection; +import org.jclouds.vcloud.domain.NetworkConnectionSection; + +import com.google.common.base.Throwables; +import com.google.inject.Inject; +import com.jamesmurty.utils.XMLBuilder; + +/** + * + * @author Adrian Cole + * + */ +@Singleton +public class BindNetworkConnectionSectionToXmlPayload extends BindToStringPayload { + @Resource + protected Logger logger = Logger.NULL; + + protected final String ns; + protected final String schema; + + @Inject + public BindNetworkConnectionSectionToXmlPayload(BindToStringPayload stringBinder, + @Named(PROPERTY_VCLOUD_XML_NAMESPACE) String ns, @Named(PROPERTY_VCLOUD_XML_SCHEMA) String schema) { + this.ns = ns; + this.schema = schema; + } + + @Override + public R bindToRequest(R request, Object payload) { + checkArgument(checkNotNull(payload, "NetworkConnectionSection") instanceof NetworkConnectionSection, + "this binder is only valid for NetworkConnectionSection!"); + NetworkConnectionSection net = NetworkConnectionSection.class.cast(payload); + XMLBuilder networkConnectionSection; + try { + networkConnectionSection = XMLBuilder.create("NetworkConnectionSection").a("xmlns", ns) + .a("xmlns:ovf", "http://schemas.dmtf.org/ovf/envelope/1").a("type", net.getType()) + .a("href", net.getHref().toASCIIString()).a("ovf:required", "false"); + networkConnectionSection.e("ovf:Info").t(net.getInfo()); + + if (net.getPrimaryNetworkConnectionIndex() != null) + networkConnectionSection.e("PrimaryNetworkConnectionIndex").t( + net.getPrimaryNetworkConnectionIndex().toString()); + for (NetworkConnection networkConnection : net.getConnections()) { + XMLBuilder networkConnectionSectionChild = networkConnectionSection.e("NetworkConnection").a("network", + networkConnection.getNetwork()); + networkConnectionSectionChild.e("NetworkConnectionIndex").t( + networkConnection.getNetworkConnectionIndex() + ""); + if (networkConnection.getExternalIpAddress() != null) + networkConnectionSectionChild.e("ExternalIpAddress").t(networkConnection.getExternalIpAddress()); + if (networkConnection.getIpAddress() != null) + networkConnectionSectionChild.e("IpAddress").t(networkConnection.getIpAddress()); + networkConnectionSectionChild.e("IsConnected").t(networkConnection.isConnected() + ""); + if (networkConnection.getMACAddress() != null) + networkConnectionSectionChild.e("MACAddress").t(networkConnection.getMACAddress()); + if (networkConnection.getIpAddressAllocationMode() != null) + networkConnectionSectionChild.e("IpAddressAllocationMode").t( + networkConnection.getIpAddressAllocationMode().toString()); + } + + if (net.getEdit() != null) + networkConnectionSection.e("Link").a("rel", "edit").a("type", net.getType()) + .a("href", net.getHref().toASCIIString()); + + Properties outputProperties = new Properties(); + outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes"); + request = super.bindToRequest(request, networkConnectionSection.asString(outputProperties)); + request.getPayload().getContentMetadata().setContentType(net.getType()); + } catch (Exception e) { + Throwables.propagate(e); + } + return request; + } + +} diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/options/VCloudTemplateOptions.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/options/VCloudTemplateOptions.java index 8214f4587f..584ec7079f 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/options/VCloudTemplateOptions.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/options/VCloudTemplateOptions.java @@ -24,6 +24,7 @@ import java.util.Arrays; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.io.Payload; import org.jclouds.util.Preconditions2; +import org.jclouds.vcloud.domain.network.IpAddressAllocationMode; /** * Contains options supported in the {@code ComputeService#runNode} operation on the "vcloud" @@ -45,6 +46,7 @@ import org.jclouds.util.Preconditions2; public class VCloudTemplateOptions extends TemplateOptions { private String customizationScript = null; + private IpAddressAllocationMode ipAddressAllocationMode = null; public static final VCloudTemplateOptions NONE = new VCloudTemplateOptions(); @@ -57,8 +59,15 @@ public class VCloudTemplateOptions extends TemplateOptions { return this; } - public static class Builder { + /** + * Specifies the ipAddressAllocationMode used to for network interfaces on the VMs + */ + public VCloudTemplateOptions ipAddressAllocationMode(IpAddressAllocationMode ipAddressAllocationMode) { + this.ipAddressAllocationMode = ipAddressAllocationMode; + return this; + } + public static class Builder { /** * @see VCloudTemplateOptions#customizationScript */ @@ -67,6 +76,14 @@ public class VCloudTemplateOptions extends TemplateOptions { return VCloudTemplateOptions.class.cast(options.customizationScript(customizationScript)); } + /** + * @see VCloudTemplateOptions#ipAddressAllocationMode + */ + public static VCloudTemplateOptions ipAddressAllocationMode(IpAddressAllocationMode ipAddressAllocationMode) { + VCloudTemplateOptions options = new VCloudTemplateOptions(); + return VCloudTemplateOptions.class.cast(options.ipAddressAllocationMode(ipAddressAllocationMode)); + } + // methods that only facilitate returning the correct object type /** * @see TemplateOptions#inboundPorts @@ -125,6 +142,13 @@ public class VCloudTemplateOptions extends TemplateOptions { return customizationScript; } + /** + * @return ipAddressAllocationMode on the vms + */ + public IpAddressAllocationMode getIpAddressAllocationMode() { + return ipAddressAllocationMode; + } + // methods that only facilitate returning the correct object type /** @@ -212,6 +236,7 @@ public class VCloudTemplateOptions extends TemplateOptions { final int prime = 31; int result = super.hashCode(); result = prime * result + ((customizationScript == null) ? 0 : customizationScript.hashCode()); + result = prime * result + ((ipAddressAllocationMode == null) ? 0 : ipAddressAllocationMode.hashCode()); return result; } @@ -229,15 +254,17 @@ public class VCloudTemplateOptions extends TemplateOptions { return false; } else if (!customizationScript.equals(other.customizationScript)) return false; + if (ipAddressAllocationMode != other.ipAddressAllocationMode) + return false; return true; } @Override public String toString() { - return "[customizationScript=" + customizationScript + ", inboundPorts=" + Arrays.toString(inboundPorts) - + ", privateKey=" + (privateKey != null) + ", publicKey=" + (publicKey != null) + ", runScript=" - + (script != null) + ", port:seconds=" + port + ":" + seconds + ", metadata/details: " + includeMetadata - + "]"; + return "[customizationScript=" + (customizationScript != null) + ", ipAddressAllocationMode=" + + ipAddressAllocationMode + ", inboundPorts=" + Arrays.toString(inboundPorts) + ", privateKey=" + + (privateKey != null) + ", publicKey=" + (publicKey != null) + ", runScript=" + (script != null) + + ", port:seconds=" + port + ":" + seconds + ", metadata/details: " + includeMetadata + "]"; } } diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java index c49fa8ebf1..095f50934a 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.java @@ -38,11 +38,16 @@ import org.jclouds.logging.Logger; import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.compute.options.VCloudTemplateOptions; import org.jclouds.vcloud.domain.GuestCustomizationSection; +import org.jclouds.vcloud.domain.NetworkConnection; +import org.jclouds.vcloud.domain.NetworkConnectionSection; +import org.jclouds.vcloud.domain.NetworkConnectionSection.Builder; import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.VApp; import org.jclouds.vcloud.domain.Vm; +import org.jclouds.vcloud.domain.network.IpAddressAllocationMode; import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; +import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; @@ -50,7 +55,8 @@ import com.google.common.collect.Iterables; * @author Adrian Cole */ @Singleton -public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn implements CreateNodeWithGroupEncodedIntoName { +public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn implements + CreateNodeWithGroupEncodedIntoName { @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; @@ -60,8 +66,8 @@ public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployA protected final Predicate successTester; @Inject - protected InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn(Predicate successTester, VCloudClient client, - GetNodeMetadataStrategy getNode) { + protected InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn(Predicate successTester, + VCloudClient client, GetNodeMetadataStrategy getNode) { this.client = client; this.successTester = successTester; this.getNode = getNode; @@ -70,13 +76,15 @@ public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployA @Override public NodeMetadata createNodeWithGroupEncodedIntoName(String tag, String name, Template template) { InstantiateVAppTemplateOptions options = processorCount((int) getCores(template.getHardware())).memory( - template.getHardware().getRam()).disk( - (long) ((template.getHardware().getVolumes().get(0).getSize()) * 1024 * 1024l)); + template.getHardware().getRam()).disk( + (long) ((template.getHardware().getVolumes().get(0).getSize()) * 1024 * 1024l)); String customizationScript = null; + IpAddressAllocationMode ipAddressAllocationMode = null; if (template.getOptions() instanceof VCloudTemplateOptions) { customizationScript = VCloudTemplateOptions.class.cast(template.getOptions()).getCustomizationScript(); - if (customizationScript != null) { + ipAddressAllocationMode = VCloudTemplateOptions.class.cast(template.getOptions()).getIpAddressAllocationMode(); + if (customizationScript != null || ipAddressAllocationMode != null) { options.customizeOnInstantiate(false); options.deploy(false); options.powerOn(false); @@ -96,39 +104,64 @@ public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployA Task task = vAppResponse.getTasks().get(0); - if (customizationScript == null) { + if (customizationScript == null && ipAddressAllocationMode == null) { return blockOnDeployAndPowerOnIfConfigured(options, vAppResponse, task); } else { if (!successTester.apply(task.getHref())) { - throw new RuntimeException(String - .format("failed to %s %s: %s", "instantiate", vAppResponse.getName(), task)); + throw new RuntimeException( + String.format("failed to %s %s: %s", "instantiate", vAppResponse.getName(), task)); } Vm vm = Iterables.get(client.getVApp(vAppResponse.getHref()).getChildren(), 0); - GuestCustomizationSection guestConfiguration = vm.getGuestCustomizationSection(); - // guestConfiguration - // .setCustomizationScript(guestConfiguration.getCustomizationScript() - // != null ? - // guestConfiguration - // .getCustomizationScript() - // + "\n" + customizationScript : customizationScript); - guestConfiguration.setCustomizationScript(customizationScript); - task = client.updateGuestCustomizationOfVm(vm.getHref(), guestConfiguration); - if (!successTester.apply(task.getHref())) { - throw new RuntimeException(String.format("failed to %s %s: %s", "updateGuestCustomizationOfVm", vm - .getName(), task)); - } + if (customizationScript != null) + updateVmWithCustomizationScript(vm, customizationScript); + if (ipAddressAllocationMode != null) + updateVmWithIpAddressAllocationMode(vm, ipAddressAllocationMode); task = client.deployAndPowerOnVAppOrVm(vAppResponse.getHref()); return blockOnDeployAndPowerOnIfConfigured(options, vAppResponse, task); } } + public void updateVmWithCustomizationScript(Vm vm, String customizationScript) { + Task task; + GuestCustomizationSection guestConfiguration = vm.getGuestCustomizationSection(); + // TODO: determine if the server version is beyond 1.0.0, and if so append to, but + // not overwrite the customization script. In version 1.0.0, the api returns a script that + // loses newlines. + guestConfiguration.setCustomizationScript(customizationScript); + task = client.updateGuestCustomizationOfVm(vm.getHref(), guestConfiguration); + if (!successTester.apply(task.getHref())) { + throw new RuntimeException(String.format("failed to %s %s: %s", "updateGuestCustomizationOfVm", vm.getName(), + task)); + } + } + + public void updateVmWithIpAddressAllocationMode(Vm vm, final IpAddressAllocationMode ipAddressAllocationMode) { + Task task; + NetworkConnectionSection net = vm.getNetworkConnectionSection(); + Builder builder = net.toBuilder(); + builder.connections(Iterables.transform(net.getConnections(), + new Function() { + + @Override + public NetworkConnection apply(NetworkConnection arg0) { + return arg0.toBuilder().connected(true).ipAddressAllocationMode(ipAddressAllocationMode).build(); + } + + })); + task = client.updateNetworkConnectionOfVm(vm.getHref(), builder.build()); + if (!successTester.apply(task.getHref())) { + throw new RuntimeException(String.format("failed to %s %s: %s", "updateNetworkConnectionOfVm", vm.getName(), + task)); + } + } + private NodeMetadata blockOnDeployAndPowerOnIfConfigured(InstantiateVAppTemplateOptions options, VApp vAppResponse, - Task task) { + Task task) { if (options.shouldBlock()) { if (!successTester.apply(task.getHref())) { - throw new RuntimeException(String.format("failed to %s %s: %s", "deploy and power on", vAppResponse - .getName(), task)); + throw new RuntimeException(String.format("failed to %s %s: %s", "deploy and power on", + vAppResponse.getName(), task)); } logger.debug("<< ready vApp(%s)", vAppResponse.getName()); } diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/NetworkConnection.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/NetworkConnection.java index 061367331a..a0c1c95daa 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/NetworkConnection.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/NetworkConnection.java @@ -29,6 +29,67 @@ import org.jclouds.vcloud.domain.network.IpAddressAllocationMode; * @author Adrian Cole */ public class NetworkConnection { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private String network; + private int networkConnectionIndex; + private String ipAddress; + private String externalIpAddress; + private boolean connected; + private String MACAddress; + private IpAddressAllocationMode ipAddressAllocationMode; + + public Builder network(String network) { + this.network = network; + return this; + } + + public Builder networkConnectionIndex(int networkConnectionIndex) { + this.networkConnectionIndex = networkConnectionIndex; + return this; + } + + public Builder ipAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + public Builder externalIpAddress(String externalIpAddress) { + this.externalIpAddress = externalIpAddress; + return this; + } + + public Builder connected(boolean connected) { + this.connected = connected; + return this; + } + + public Builder MACAddress(String MACAddress) { + this.MACAddress = MACAddress; + return this; + } + + public Builder ipAddressAllocationMode(IpAddressAllocationMode ipAddressAllocationMode) { + this.ipAddressAllocationMode = ipAddressAllocationMode; + return this; + } + + public NetworkConnection build() { + return new NetworkConnection(network, networkConnectionIndex, ipAddress, externalIpAddress, connected, + MACAddress, ipAddressAllocationMode); + } + + public static Builder fromNetworkConnection(NetworkConnection in) { + return new Builder().network(in.getNetwork()).networkConnectionIndex(in.getNetworkConnectionIndex()) + .ipAddress(in.getIpAddress()).externalIpAddress(in.getExternalIpAddress()).connected(in.isConnected()) + .MACAddress(in.getMACAddress()).ipAddressAllocationMode(in.getIpAddressAllocationMode()); + } + } + private final String network; private final int networkConnectionIndex; @Nullable @@ -41,8 +102,8 @@ public class NetworkConnection { private final IpAddressAllocationMode ipAddressAllocationMode; public NetworkConnection(String network, int networkConnectionIndex, @Nullable String ipAddress, - @Nullable String externalIpAddress, boolean connected, @Nullable String MACAddress, - IpAddressAllocationMode ipAddressAllocationMode) { + @Nullable String externalIpAddress, boolean connected, @Nullable String MACAddress, + IpAddressAllocationMode ipAddressAllocationMode) { this.network = network; this.networkConnectionIndex = networkConnectionIndex; this.ipAddress = ipAddress; @@ -162,11 +223,15 @@ public class NetworkConnection { return true; } + public Builder toBuilder() { + return Builder.fromNetworkConnection(this); + } + @Override public String toString() { return "[network=" + network + ", connected=" + connected + ", ipAddress=" + ipAddress + ", externalIpAddress=" - + externalIpAddress + ", networkConnectionIndex=" + networkConnectionIndex - + ", ipAddressAllocationMode=" + ipAddressAllocationMode + ", MACAddress=" + MACAddress + "]"; + + externalIpAddress + ", networkConnectionIndex=" + networkConnectionIndex + ", ipAddressAllocationMode=" + + ipAddressAllocationMode + ", MACAddress=" + MACAddress + "]"; } } \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/NetworkConnectionSection.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/NetworkConnectionSection.java index 5c693210f7..47e19eb938 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/NetworkConnectionSection.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/NetworkConnectionSection.java @@ -24,8 +24,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.net.URI; import java.util.Set; -import com.google.common.collect.Iterables; -import com.google.common.collect.Sets; +import com.google.common.collect.ImmutableSet; /** * The NetworkConnectionSection element specifies how a Vm is connected to a vApp network. It @@ -36,20 +35,73 @@ import com.google.common.collect.Sets; * values specified in the NetworkConnectionSection override those specified in the NetworkSection. */ public class NetworkConnectionSection { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + protected String type; + protected URI href; + protected String info; + protected Integer primaryNetworkConnectionIndex; + protected Set connections = ImmutableSet.of(); + protected ReferenceType edit; + + public Builder type(String type) { + this.type = type; + return this; + } + + public Builder href(URI href) { + this.href = href; + return this; + } + + public Builder info(String info) { + this.info = info; + return this; + } + + public Builder primaryNetworkConnectionIndex(Integer primaryNetworkConnectionIndex) { + this.primaryNetworkConnectionIndex = primaryNetworkConnectionIndex; + return this; + } + + public Builder connections(Iterable connections) { + this.connections = ImmutableSet.copyOf(checkNotNull(connections, "connections")); + return this; + } + + public Builder edit(ReferenceType edit) { + this.edit = edit; + return this; + } + + public NetworkConnectionSection build() { + return new NetworkConnectionSection(type, href, info, primaryNetworkConnectionIndex, connections, edit); + } + + public static Builder fromNetworkConnectionSection(NetworkConnectionSection in) { + return new Builder().type(in.getType()).href(in.getHref()).info(in.getInfo()) + .primaryNetworkConnectionIndex(in.getPrimaryNetworkConnectionIndex()).connections(in.getConnections()) + .edit(in.getEdit()); + } + } + protected final String type; protected final URI href; protected final String info; protected final Integer primaryNetworkConnectionIndex; - protected final Set connections = Sets.newLinkedHashSet(); + protected final Set connections; protected final ReferenceType edit; public NetworkConnectionSection(String type, URI href, String info, Integer primaryNetworkConnectionIndex, - Iterable connections, ReferenceType edit) { + Iterable connections, ReferenceType edit) { this.type = type; this.href = href; this.info = info; this.primaryNetworkConnectionIndex = primaryNetworkConnectionIndex; - Iterables.addAll(this.connections, checkNotNull(connections, "connections")); + this.connections = ImmutableSet.copyOf(checkNotNull(connections, "connections")); this.edit = edit; } @@ -109,7 +161,7 @@ public class NetworkConnectionSection { result = prime * result + ((href == null) ? 0 : href.hashCode()); result = prime * result + ((info == null) ? 0 : info.hashCode()); result = prime * result - + ((primaryNetworkConnectionIndex == null) ? 0 : primaryNetworkConnectionIndex.hashCode()); + + ((primaryNetworkConnectionIndex == null) ? 0 : primaryNetworkConnectionIndex.hashCode()); result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } @@ -156,10 +208,14 @@ public class NetworkConnectionSection { return true; } + public Builder toBuilder() { + return Builder.fromNetworkConnectionSection(this); + } + @Override public String toString() { return "[href=" + href + ", connections=" + connections + ", primaryNetworkConnectionIndex=" - + primaryNetworkConnectionIndex + "]"; + + primaryNetworkConnectionIndex + "]"; } } \ No newline at end of file diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindNetworkConnectionSectionToXmlPayloadTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindNetworkConnectionSectionToXmlPayloadTest.java new file mode 100644 index 0000000000..e9845644e9 --- /dev/null +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindNetworkConnectionSectionToXmlPayloadTest.java @@ -0,0 +1,86 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.testng.Assert.assertEquals; + +import java.io.IOException; +import java.net.URI; +import java.util.Properties; + +import org.jclouds.http.HttpRequest; +import org.jclouds.vcloud.VCloudPropertiesBuilder; +import org.jclouds.vcloud.domain.NetworkConnection; +import org.jclouds.vcloud.domain.NetworkConnectionSection; +import org.jclouds.vcloud.domain.network.IpAddressAllocationMode; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +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 BindNetworkConnectionSectionToXmlPayload} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class BindNetworkConnectionSectionToXmlPayloadTest { + 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 testWithIpAllocationModeNONE() throws IOException { + + @SuppressWarnings("rawtypes") + HttpRequest request = new HttpRequest.Builder().endpoint(URI.create("http://localhost/key")).method("GET") + .build(); + + BindNetworkConnectionSectionToXmlPayload binder = injector + .getInstance(BindNetworkConnectionSectionToXmlPayload.class); + + binder.bindToRequest( + request, + NetworkConnectionSection + .builder() + .type("application/vnd.vmware.vcloud.networkConnectionSection+xml") + .info("Specifies the available VM network connections") + .href(URI.create("https://1.1.1.1/api/v1.0/vApp/vm-1/networkConnectionSection/")) + .connections( + ImmutableSet. of(NetworkConnection.builder().network("none") + .ipAddressAllocationMode(IpAddressAllocationMode.NONE).build())).build()); + assertEquals(request.getPayload().getContentMetadata().getContentType(), + "application/vnd.vmware.vcloud.networkConnectionSection+xml"); + + assertEquals( + request.getPayload().getRawContent(), + "Specifies the available VM network connections0falseNONE"); + + } + +} diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/options/VCloudTemplateOptionsTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/options/VCloudTemplateOptionsTest.java index d1c4333234..5fac22935e 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/options/VCloudTemplateOptionsTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/options/VCloudTemplateOptionsTest.java @@ -24,12 +24,14 @@ import static org.jclouds.vcloud.compute.options.VCloudTemplateOptions.Builder.b import static org.jclouds.vcloud.compute.options.VCloudTemplateOptions.Builder.customizationScript; import static org.jclouds.vcloud.compute.options.VCloudTemplateOptions.Builder.inboundPorts; import static org.jclouds.vcloud.compute.options.VCloudTemplateOptions.Builder.installPrivateKey; +import static org.jclouds.vcloud.compute.options.VCloudTemplateOptions.Builder.ipAddressAllocationMode; import static org.testng.Assert.assertEquals; import java.io.IOException; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.io.Payloads; +import org.jclouds.vcloud.domain.network.IpAddressAllocationMode; import org.testng.annotations.Test; /** @@ -38,6 +40,18 @@ import org.testng.annotations.Test; * @author Adrian Cole */ public class VCloudTemplateOptionsTest { + @Test + public void testipAddressAllocationMode() { + VCloudTemplateOptions options = new VCloudTemplateOptions(); + options.ipAddressAllocationMode(IpAddressAllocationMode.NONE); + assertEquals(options.getIpAddressAllocationMode(), IpAddressAllocationMode.NONE); + } + + @Test + public void testipAddressAllocationModeStatic() { + VCloudTemplateOptions options = ipAddressAllocationMode(IpAddressAllocationMode.NONE); + assertEquals(options.getIpAddressAllocationMode(), IpAddressAllocationMode.NONE); + } public void testAs() { TemplateOptions options = new VCloudTemplateOptions(); @@ -50,6 +64,12 @@ public class VCloudTemplateOptionsTest { options.customizationScript(""); } + @Test + public void testNullcustomizationScript() { + VCloudTemplateOptions options = new VCloudTemplateOptions(); + assertEquals(options.getCustomizationScript(), null); + } + @Test public void testcustomizationScript() { VCloudTemplateOptions options = new VCloudTemplateOptions(); @@ -57,12 +77,6 @@ public class VCloudTemplateOptionsTest { assertEquals(options.getCustomizationScript(), "mykeypair"); } - @Test - public void testNullcustomizationScript() { - VCloudTemplateOptions options = new VCloudTemplateOptions(); - assertEquals(options.getCustomizationScript(), null); - } - @Test public void testcustomizationScriptStatic() { VCloudTemplateOptions options = customizationScript("mykeypair");