Issue 290: added guest customization support

This commit is contained in:
Adrian Cole 2010-09-05 00:20:45 -07:00
parent e5bd9bbfb8
commit 36dec74379
22 changed files with 1438 additions and 266 deletions

View File

@ -0,0 +1,44 @@
/**
*
* 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.bluelock;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.vcloud.VCloudGuestCustomizationLiveTest;
import org.testng.annotations.Test;
/**
*
*
* @author Adrian Cole
*/
@Test(groups = "live", enabled = true, sequential = true, testName = "vcloud.BlueLockVCloudDirectorGuestCustomizationLiveTest")
public class BlueLockVCloudDirectorGuestCustomizationLiveTest extends VCloudGuestCustomizationLiveTest {
@Override
protected void setupCredentials() {
provider = "bluelock-vclouddirector";
identity = checkNotNull(System.getProperty("bluelock-vclouddirector.identity"),
"bluelock-vclouddirector.identity");
credential = checkNotNull(System.getProperty("bluelock-vclouddirector.credential"),
"bluelock-vclouddirector.credential");
}
}

View File

@ -20,6 +20,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.TASK_XML;
import static org.jclouds.vcloud.VCloudMediaType.UNDEPLOYVAPPPARAMS_XML;
import static org.jclouds.vcloud.VCloudMediaType.VAPPTEMPLATE_XML;
@ -34,11 +35,13 @@ import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jclouds.predicates.validators.DnsNameValidator;
import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.EndpointParam;
import org.jclouds.rest.annotations.ExceptionParser;
@ -52,8 +55,10 @@ import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
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.BindUndeployVAppParamsToXmlPayload;
import org.jclouds.vcloud.domain.GuestCustomizationSection;
import org.jclouds.vcloud.domain.ReferenceType;
import org.jclouds.vcloud.domain.Task;
import org.jclouds.vcloud.domain.VApp;
@ -79,8 +84,7 @@ import com.google.common.util.concurrent.ListenableFuture;
* Provides access to VCloud resources via their REST API.
* <p/>
*
* @see <a href="https://community.vcloudexpress.terremark.com/en-us/discussion_forums/f/60.aspx"
* />
* @see <a href="https://community.vcloudexpress.terremark.com/en-us/discussion_forums/f/60.aspx" />
* @author Adrian Cole
*/
@RequestFilters(SetVCloudTokenCookie.class)
@ -183,6 +187,18 @@ public interface VCloudAsyncClient extends CommonVCloudAsyncClient {
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
ListenableFuture<? extends Vm> getVm(@EndpointParam URI vm);
/**
* @see VCloudClient#updateGuestCustomizationOfVm
*/
@PUT
@Consumes(TASK_XML)
@Produces(GUESTCUSTOMIZATIONSECTION_XML)
@Path("/guestCustomizationSection")
@XMLResponseParser(TaskHandler.class)
ListenableFuture<? extends Task> updateGuestCustomizationOfVm(
@EndpointParam URI vm,
@BinderParam(BindGuestCustomizationSectionToXmlPayload.class) GuestCustomizationSection guestCustomizationSection);
/**
* @see VCloudClient#deployVAppOrVm
*/

View File

@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import org.jclouds.concurrent.Timeout;
import org.jclouds.vcloud.domain.GuestCustomizationSection;
import org.jclouds.vcloud.domain.ReferenceType;
import org.jclouds.vcloud.domain.Task;
import org.jclouds.vcloud.domain.VApp;
@ -40,16 +41,14 @@ import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
* Provides access to VCloud resources via their REST API.
* <p/>
*
* @see <a
* href="http://communities.vmware.com/community/developer/forums/vcloudapi"
* />
* @see <a href="http://communities.vmware.com/community/developer/forums/vcloudapi" />
* @author Adrian Cole
*/
@Timeout(duration = 300, timeUnit = TimeUnit.SECONDS)
public interface VCloudClient extends CommonVCloudClient {
/**
* The response to a login request includes a list of the organizations to
* which the authenticated user has access.
* The response to a login request includes a list of the organizations to which the
* authenticated user has access.
*
* @return organizations indexed by name
*/
@ -64,9 +63,19 @@ public interface VCloudClient extends CommonVCloudClient {
OvfEnvelope getOvfEnvelopeForVAppTemplate(URI vAppTemplate);
/**
* 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.
* Modify the Guest Customization Section of a Virtual Machine
*
* @param vm
* uri to modify
* @param updated
* guestCustomizationSection
* @return task in progress
*/
Task updateGuestCustomizationOfVm(URI vm, GuestCustomizationSection 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.
*
* @param orgName
* organization name, or null for the default
@ -76,8 +85,7 @@ public interface VCloudClient extends CommonVCloudClient {
* item you wish to lookup
*
* @throws NoSuchElementException
* if you specified an org, catalog, or catalog item name that
* isn't present
* if you specified an org, catalog, or catalog item name that isn't present
*/
VAppTemplate findVAppTemplateInOrgCatalogNamed(@Nullable String orgName, @Nullable String catalogName,
String itemName);
@ -89,109 +97,97 @@ public interface VCloudClient extends CommonVCloudClient {
Vm getVm(URI vm);
/**
* To deploy a vApp, the client makes a request to its action/deploy URL.
* Deploying a vApp automatically deploys all of the virtual machines it
* contains. To deploy a virtual machine, the client makes a request to its
* action/deploy URL.
* To deploy a vApp, the client makes a request to its action/deploy URL. Deploying a vApp
* automatically deploys all of the virtual machines it contains. To deploy a virtual machine,
* the client makes a request to its action/deploy URL.
* <p/>
* Deploying a Vm implicitly deploys the parent vApp if that vApp is not
* already deployed.
* Deploying a Vm implicitly deploys the parent vApp if that vApp is not already deployed.
*/
Task deployVAppOrVm(URI vAppOrVmId);
/**
* like {@link #deployVAppOrVm(URI)}, except deploy transistions to power on
* state
* like {@link #deployVAppOrVm(URI)}, except deploy transistions to power on state
*
*/
Task deployAndPowerOnVAppOrVm(URI vAppOrVmId);
/**
* Undeploying a vApp powers off or suspends any running virtual machines it
* contains, then frees the resources reserved for the vApp and sets the
* vApps deploy attribute to a value of false to indicate that it is not
* deployed.
* Undeploying a vApp powers off or suspends any running virtual machines it contains, then frees
* the resources reserved for the vApp and sets the vApps deploy attribute to a value of false
* to indicate that it is not deployed.
* <p/>
* Undeploying a virtual machine powers off or suspends the virtual machine,
* then frees the resources reserved for it and sets the its deploy attribute
* to a value of false to indicate that it is not deployed. This operation
* has no effect on the containing vApp.
* Undeploying a virtual machine powers off or suspends the virtual machine, then frees the
* resources reserved for it and sets the its deploy attribute to a value of false to indicate
* that it is not deployed. This operation has no effect on the containing vApp.
* <h4>NOTE</h4>
* Using this method will simply power off the vms. In order to save their
* state, use {@link #undeployAndSaveStateOfVAppOrVm}
* Using this method will simply power off the vms. In order to save their state, use
* {@link #undeployAndSaveStateOfVAppOrVm}
*
*/
Task undeployVAppOrVm(URI vAppOrVmId);
/**
* like {@link #undeployVAppOrVm(URI)}, where the undeployed virtual machines
* are suspended and their suspend state saved
* like {@link #undeployVAppOrVm(URI)}, where the undeployed virtual machines are suspended and
* their suspend state saved
*
*/
Task undeployAndSaveStateOfVAppOrVm(URI vAppOrVmId);
/**
* A powerOn request to a vApp URL powers on all of the virtual machines in
* the vApp, as specified in the vApps StartupSection field.
* A powerOn request to a vApp URL powers on all of the virtual machines in the vApp, as
* specified in the vApps StartupSection field.
* <p/>
* A powerOn request to a virtual machine URL powers on the specified virtual
* machine and forces deployment of the parent vApp.
* A powerOn request to a virtual machine URL powers on the specified virtual machine and forces
* deployment of the parent vApp.
* <p/>
* <h4>NOTE</h4> A powerOn request to a vApp or virtual machine that is
* undeployed forces deployment.
* <h4>NOTE</h4> A powerOn request to a vApp or virtual machine that is undeployed forces
* deployment.
*/
Task powerOnVAppOrVm(URI vAppOrVmId);
/**
* A powerOff request to a vApp URL powers off all of the virtual machines in
* the vApp, as specified in its StartupSection field.
* A powerOff request to a vApp URL powers off all of the virtual machines in the vApp, as
* specified in its StartupSection field.
* <p/>
* A powerOff request to a virtual machine URL powers off the specified
* virtual machine.
* A powerOff request to a virtual machine URL powers off the specified virtual machine.
*/
Task powerOffVAppOrVm(URI vAppOrVmId);
/**
* A shutdown request to a vApp URL shuts down all of the virtual machines in
* the vApp, as specified in its StartupSection field.
* A shutdown request to a vApp URL shuts down all of the virtual machines in the vApp, as
* specified in its StartupSection field.
* <p/>
* A shutdown request to a virtual machine URL shuts down the specified
* virtual machine.
* A shutdown request to a virtual machine URL shuts down the specified virtual machine.
* <p/>
* <h4>NOTE</h4Because this request sends a signal to the guest OS, the
* vCloud API cannot track the progress or verify the result of the requested
* operation. Hence, void is returned
* <h4>NOTE</h4Because this request sends a signal to the guest OS, the vCloud API cannot track
* the progress or verify the result of the requested operation. Hence, void is returned
*/
void shutdownVAppOrVm(URI vAppOrVmId);
/**
* A reset request to a vApp URL resets all of the virtual machines in the
* vApp, as specified in its StartupSection field.
* A reset request to a vApp URL resets all of the virtual machines in the vApp, as specified in
* its StartupSection field.
* <p/>
* A reset request to a virtual machine URL resets the specified virtual
* machine.
* A reset request to a virtual machine URL resets the specified virtual machine.
*/
Task resetVAppOrVm(URI vAppOrVmId);
/**
* A reboot request to a vApp URL reboots all of the virtual machines in the
* vApp, as specified in its StartupSection field.
* A reboot request to a vApp URL reboots all of the virtual machines in the vApp, as specified
* in its StartupSection field.
* <p/>
* A reboot request to a virtual machine URL reboots the specified virtual
* machine.
* A reboot request to a virtual machine URL reboots the specified virtual machine.
* <p/>
* <h4>NOTE</h4> Because this request sends a signal to the guest OS, the
* vCloud API cannot track the progress or verify the result of the requested
* operation. Hence, void is returned
* <h4>NOTE</h4> Because this request sends a signal to the guest OS, the vCloud API cannot track
* the progress or verify the result of the requested operation. Hence, void is returned
*/
void rebootVAppOrVm(URI vAppOrVmId);
/**
* A suspend request to a vApp URL suspends all of the virtual machines in
* the vApp, as specified in its StartupSection field.
* A suspend request to a vApp URL suspends all of the virtual machines in the vApp, as specified
* in its StartupSection field.
* <p/>
* A suspend request to a virtual machine URL suspends the specified virtual
* machine.
* A suspend request to a virtual machine URL suspends the specified virtual machine.
*/
Task suspendVAppOrVm(URI vAppOrVmId);

View File

@ -0,0 +1,115 @@
/**
*
* 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 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.GuestCustomizationSection;
import com.google.common.base.Throwables;
import com.google.inject.Inject;
import com.jamesmurty.utils.XMLBuilder;
/**
*
* @author Adrian Cole
*
*/
@Singleton
public class BindGuestCustomizationSectionToXmlPayload extends BindToStringPayload {
@Resource
protected Logger logger = Logger.NULL;
protected final String ns;
protected final String schema;
@Inject
public BindGuestCustomizationSectionToXmlPayload(BindToStringPayload stringBinder,
@Named(PROPERTY_VCLOUD_XML_NAMESPACE) String ns, @Named(PROPERTY_VCLOUD_XML_SCHEMA) String schema) {
this.ns = ns;
this.schema = schema;
}
public void bindToRequest(HttpRequest request, Object payload) {
checkArgument(checkNotNull(payload, "GuestCustomizationSection") instanceof GuestCustomizationSection,
"this binder is only valid for GuestCustomizationSection!");
GuestCustomizationSection guest = GuestCustomizationSection.class.cast(payload);
XMLBuilder guestCustomizationSection;
try {
guestCustomizationSection = XMLBuilder.create("GuestCustomizationSection").a("xmlns", ns).a("xmlns:ovf",
"http://schemas.dmtf.org/ovf/envelope/1").a("type", guest.getType()).a("href",
guest.getHref().toASCIIString()).a("ovf:required", "false");
guestCustomizationSection.e("ovf:Info").t(guest.getInfo());
if (guest.isEnabled() != null)
guestCustomizationSection.e("Enabled").t(guest.isEnabled().toString());
if (guest.shouldChangeSid() != null)
guestCustomizationSection.e("ChangeSid").t(guest.shouldChangeSid().toString());
if (guest.getVirtualMachineId() != null)
guestCustomizationSection.e("VirtualMachineId").t(guest.getVirtualMachineId().toString());
if (guest.isJoinDomainEnabled() != null)
guestCustomizationSection.e("JoinDomainEnabled").t(guest.isJoinDomainEnabled().toString());
if (guest.shouldUseOrgSettings() != null)
guestCustomizationSection.e("UseOrgSettings").t(guest.shouldUseOrgSettings().toString());
if (guest.getDomainName() != null)
guestCustomizationSection.e("DomainName").t(guest.getDomainName().toString());
if (guest.getDomainUserName() != null)
guestCustomizationSection.e("DomainUserName").t(guest.getDomainUserName().toString());
if (guest.getDomainUserPassword() != null)
guestCustomizationSection.e("DomainUserPassword").t(guest.getDomainUserPassword().toString());
if (guest.isAdminPasswordEnabled() != null)
guestCustomizationSection.e("AdminPasswordEnabled").t(guest.isAdminPasswordEnabled().toString());
if (guest.isAdminPasswordAuto() != null)
guestCustomizationSection.e("AdminPasswordAuto").t(guest.isAdminPasswordAuto().toString());
// if (guest.getAdminPassword() != null)
// guestCustomizationSection.e("AdminPassword").t(guest.getAdminPassword().toString());
if (guest.isResetPasswordRequired() != null)
guestCustomizationSection.e("ResetPasswordRequired").t(guest.isResetPasswordRequired().toString());
if (guest.getCustomizationScript() != null)
guestCustomizationSection.e("CustomizationScript").t(guest.getCustomizationScript());
if (guest.getComputerName() != null)
guestCustomizationSection.e("ComputerName").t(guest.getComputerName().toString());
if (guest.getEdit() != null)
guestCustomizationSection.e("Link").a("rel", "edit").a("type", guest.getType()).a("href",
guest.getHref().toASCIIString());
Properties outputProperties = new Properties();
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
super.bindToRequest(request, guestCustomizationSection.asString(outputProperties));
request.getPayload().setContentType(guest.getType());
} catch (Exception e) {
Throwables.propagate(e);
}
}
}

View File

@ -31,6 +31,7 @@ import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
@ -45,11 +46,13 @@ import org.jclouds.rest.binders.BindToStringPayload;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.vcloud.VCloudClient;
import org.jclouds.vcloud.domain.VAppTemplate;
import org.jclouds.vcloud.domain.Vm;
import org.jclouds.vcloud.domain.network.FenceMode;
import org.jclouds.vcloud.domain.network.NetworkConfig;
import org.jclouds.vcloud.endpoints.Network;
import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@ -73,18 +76,20 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder
protected final URI defaultNetwork;
protected final FenceMode defaultFenceMode;
protected final DefaultNetworkNameInTemplate defaultNetworkNameInTemplate;
protected final VCloudClient client;
@Inject
public BindInstantiateVAppTemplateParamsToXmlPayload(DefaultNetworkNameInTemplate defaultNetworkNameInTemplate,
BindToStringPayload stringBinder, @Named(PROPERTY_VCLOUD_XML_NAMESPACE) String ns,
@Named(PROPERTY_VCLOUD_XML_SCHEMA) String schema, @Network URI network,
@Named(PROPERTY_VCLOUD_DEFAULT_FENCEMODE) String fenceMode) {
@Named(PROPERTY_VCLOUD_DEFAULT_FENCEMODE) String fenceMode, VCloudClient client) {
this.defaultNetworkNameInTemplate = defaultNetworkNameInTemplate;
this.ns = ns;
this.schema = schema;
this.stringBinder = stringBinder;
this.defaultNetwork = network;
this.defaultFenceMode = FenceMode.fromValue(fenceMode);
this.client = client;
}
@SuppressWarnings("unchecked")
@ -98,11 +103,12 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder
boolean deploy = true;
boolean powerOn = true;
Boolean customizeOnInstantiate = null;
Set<? extends NetworkConfig> networkConfig = null;
NetworknetworkConfigDecorator networknetworkConfigDecorator = new NetworknetworkConfigDecorator(template,
defaultNetwork, defaultFenceMode, defaultNetworkNameInTemplate);
NetworkConfigDecorator networknetworkConfigDecorator = new NetworkConfigDecorator(template, defaultNetwork,
defaultFenceMode, defaultNetworkNameInTemplate);
InstantiateVAppTemplateOptions options = findOptionsInArgsOrNull(gRequest);
@ -110,16 +116,17 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder
if (options.getNetworkConfig().size() > 0)
networkConfig = Sets.newLinkedHashSet(Iterables.transform(options.getNetworkConfig(),
networknetworkConfigDecorator));
deploy = ifNullDefaultTo(options.shouldDeploy(), deploy);
powerOn = ifNullDefaultTo(options.shouldPowerOn(), powerOn);
customizeOnInstantiate = options.shouldCustomizeOnInstantiate();
}
if (networkConfig == null)
networkConfig = ImmutableSet.of(networknetworkConfigDecorator.apply(null));
try {
stringBinder.bindToRequest(request, generateXml(name, deploy, powerOn, template, networkConfig));
stringBinder.bindToRequest(request, generateXml(name, deploy, powerOn, template, networkConfig,
customizeOnInstantiate));
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
} catch (FactoryConfigurationError e) {
@ -130,13 +137,25 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder
}
protected static final class NetworknetworkConfigDecorator implements Function<NetworkConfig, NetworkConfig> {
@VisibleForTesting
Set<? extends Vm> ifCustomizationScriptIsSetGetVmsInTemplate(String customizationScript, final URI template) {
Set<? extends Vm> vms = Sets.newLinkedHashSet();
if (customizationScript != null) {
VAppTemplate vAppTemplate = client.getVAppTemplate(template);
checkArgument(vAppTemplate != null, "vAppTemplate %s not found!", template);
vms = vAppTemplate.getChildren();
checkArgument(vms.size() > 0, "no vms found in vAppTemplate %s", vAppTemplate);
}
return vms;
}
protected static final class NetworkConfigDecorator implements Function<NetworkConfig, NetworkConfig> {
private final URI template;
private final URI defaultNetwork;
private final FenceMode defaultFenceMode;
private final DefaultNetworkNameInTemplate defaultNetworkNameInTemplate;
protected NetworknetworkConfigDecorator(URI template, URI defaultNetwork, FenceMode defaultFenceMode,
protected NetworkConfigDecorator(URI template, URI defaultNetwork, FenceMode defaultFenceMode,
DefaultNetworkNameInTemplate defaultNetworkNameInTemplate) {
this.template = checkNotNull(template, "template");
this.defaultNetwork = checkNotNull(defaultNetwork, "defaultNetwork");
@ -180,17 +199,15 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder
networkName = Iterables.get(networks, 0).getName();
return networkName;
}
}
protected String generateXml(String name, boolean deploy, boolean powerOn, URI template,
Iterable<? extends NetworkConfig> networkConfig) throws ParserConfigurationException,
FactoryConfigurationError, TransformerException {
Iterable<? extends NetworkConfig> networkConfig, @Nullable Boolean customizeOnInstantiate)
throws ParserConfigurationException, FactoryConfigurationError, TransformerException {
XMLBuilder rootBuilder = buildRoot(name).a("deploy", deploy + "").a("powerOn", powerOn + "");
XMLBuilder instantiationParamsBuilder = rootBuilder.e("InstantiationParams");
addNetworkConfig(instantiationParamsBuilder, networkConfig);
addCustomizationConfig(instantiationParamsBuilder, customizeOnInstantiate);
rootBuilder.e("Source").a("href", template.toASCIIString());
rootBuilder.e("AllEULAsAccepted").t("true");
@ -199,6 +216,14 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder
return rootBuilder.asString(outputProperties);
}
protected void addCustomizationConfig(XMLBuilder instantiationParamsBuilder, Boolean customizeOnInstantiate) {
if (customizeOnInstantiate != null) {
// XMLBuilder customizationSectionBuilder = instantiationParamsBuilder.e("CustomizationSection");
// customizationSectionBuilder.e("ovf:Info").t("VApp template customization section");
// customizationSectionBuilder.e("CustomizeOnInstantiate").t(customizeOnInstantiate.toString());
}
}
protected void addNetworkConfig(XMLBuilder instantiationParamsBuilder,
Iterable<? extends NetworkConfig> networkConfig) {
XMLBuilder networkConfigBuilder = instantiationParamsBuilder.e("NetworkConfigSection");

View File

@ -24,7 +24,9 @@ import java.util.Set;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.internal.ComputeServiceContextImpl;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.strategy.AddNodeWithTagStrategy;
import org.jclouds.compute.strategy.DestroyNodeStrategy;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
@ -36,6 +38,8 @@ import org.jclouds.rest.internal.RestContextImpl;
import org.jclouds.vcloud.VCloudClient;
import org.jclouds.vcloud.compute.functions.ImagesInOrg;
import org.jclouds.vcloud.compute.functions.SizesInOrg;
import org.jclouds.vcloud.compute.internal.VCloudTemplateBuilderImpl;
import org.jclouds.vcloud.compute.options.VCloudTemplateOptions;
import org.jclouds.vcloud.compute.strategy.GetLoginCredentialsFromGuestConfiguration;
import org.jclouds.vcloud.compute.strategy.VCloudAddNodeWithTagStrategy;
import org.jclouds.vcloud.compute.strategy.VCloudDestroyNodeStrategy;
@ -62,6 +66,8 @@ public class VCloudComputeServiceContextModule extends CommonVCloudComputeServic
@Override
protected void configure() {
super.configure();
bind(TemplateOptions.class).to(VCloudTemplateOptions.class);
bind(TemplateBuilder.class).to(VCloudTemplateBuilderImpl.class);
bind(RebootNodeStrategy.class).to(VCloudRebootNodeStrategy.class);
bind(GetNodeMetadataStrategy.class).to(VCloudGetNodeMetadataStrategy.class);
bind(new TypeLiteral<ComputeServiceContext>() {

View File

@ -19,70 +19,38 @@
package org.jclouds.vcloud.compute.functions;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Maps.newHashMap;
import static org.jclouds.vcloud.predicates.VCloudPredicates.resourceType;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.logging.Logger;
import org.jclouds.vcloud.compute.internal.VCloudExpressComputeClientImpl;
import org.jclouds.vcloud.domain.VApp;
import org.jclouds.vcloud.domain.Vm;
import org.jclouds.vcloud.domain.ovf.ResourceAllocation;
import org.jclouds.vcloud.domain.ovf.ResourceType;
import org.jclouds.vcloud.domain.ovf.VCloudHardDisk;
import org.jclouds.vcloud.domain.ovf.VCloudNetworkAdapter;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
/**
* Configures the {@link VCloudComputeServiceContext}; requires
* {@link VCloudExpressComputeClientImpl} bound.
*
* @author Adrian Cole
*/
@Singleton
public class GetExtraFromVApp implements Function<VApp, Map<String, String>> {
private final GetExtraFromVm getExtraFromVm;
@Inject
GetExtraFromVApp(GetExtraFromVm getExtraFromVm) {
this.getExtraFromVm = getExtraFromVm;
}
@Resource
protected Logger logger = Logger.NULL;
public Map<String, String> apply(VApp vApp) {
Map<String, String> extra = newHashMap();
try {
// TODO make this work with composite vApps
Vm vm = Iterables.get(vApp.getChildren(), 0);
extra.put("memory/mb", find(vm.getVirtualHardwareSection().getResourceAllocations(), resourceType(ResourceType.MEMORY))
.getVirtualQuantity()
+ "");
extra.put("processor/count", find(vm.getVirtualHardwareSection().getResourceAllocations(),
resourceType(ResourceType.PROCESSOR)).getVirtualQuantity()
+ "");
for (ResourceAllocation disk : filter(vm.getVirtualHardwareSection().getResourceAllocations(),
resourceType(ResourceType.DISK_DRIVE))) {
if (disk instanceof VCloudHardDisk) {
VCloudHardDisk vDisk = VCloudHardDisk.class.cast(disk);
extra.put(String.format("disk_drive/%s/mb", disk.getAddressOnParent()), vDisk.getCapacity() + "");
} else {
extra.put(String.format("disk_drive/%s/kb", disk.getAddressOnParent()), disk.getVirtualQuantity() + "");
}
}
for (ResourceAllocation net : filter(vm.getVirtualHardwareSection().getResourceAllocations(),
resourceType(ResourceType.ETHERNET_ADAPTER))) {
if (net instanceof VCloudNetworkAdapter) {
VCloudNetworkAdapter vNet = VCloudNetworkAdapter.class.cast(net);
extra.put(String.format("network/%s/ip", net.getAddressOnParent()), vNet.getIpAddress());
}
}
} catch (Exception e) {
logger.error(e, "error getting extra data for vApp: %s", vApp);
}
return extra;
return vApp.getChildren().size() == 0 ? ImmutableMap.<String, String> of() : getExtraFromVm.apply(Iterables.get(
vApp.getChildren(), 0));
}
}

View File

@ -0,0 +1,81 @@
/**
*
* 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.compute.functions;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Maps.newHashMap;
import static org.jclouds.vcloud.predicates.VCloudPredicates.resourceType;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.logging.Logger;
import org.jclouds.vcloud.domain.Vm;
import org.jclouds.vcloud.domain.ovf.ResourceAllocation;
import org.jclouds.vcloud.domain.ovf.ResourceType;
import org.jclouds.vcloud.domain.ovf.VCloudHardDisk;
import org.jclouds.vcloud.domain.ovf.VCloudNetworkAdapter;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
@Singleton
public class GetExtraFromVm implements Function<Vm, Map<String, String>> {
@Resource
protected Logger logger = Logger.NULL;
public Map<String, String> apply(Vm vm) {
Map<String, String> extra = newHashMap();
try {
extra.put("memory/mb", find(vm.getVirtualHardwareSection().getResourceAllocations(),
resourceType(ResourceType.MEMORY)).getVirtualQuantity()
+ "");
extra.put("processor/count", find(vm.getVirtualHardwareSection().getResourceAllocations(),
resourceType(ResourceType.PROCESSOR)).getVirtualQuantity()
+ "");
for (ResourceAllocation disk : filter(vm.getVirtualHardwareSection().getResourceAllocations(),
resourceType(ResourceType.DISK_DRIVE))) {
if (disk instanceof VCloudHardDisk) {
VCloudHardDisk vDisk = VCloudHardDisk.class.cast(disk);
extra.put(String.format("disk_drive/%s/mb", disk.getAddressOnParent()), vDisk.getCapacity() + "");
} else {
extra.put(String.format("disk_drive/%s/kb", disk.getAddressOnParent()), disk.getVirtualQuantity() + "");
}
}
for (ResourceAllocation net : filter(vm.getVirtualHardwareSection().getResourceAllocations(),
resourceType(ResourceType.ETHERNET_ADAPTER))) {
if (net instanceof VCloudNetworkAdapter) {
VCloudNetworkAdapter vNet = VCloudNetworkAdapter.class.cast(net);
extra.put(String.format("network/%s/ip", net.getAddressOnParent()), vNet.getIpAddress());
}
}
} catch (Exception e) {
logger.error(e, "error getting extra data for vm: %s", vm);
}
return extra;
}
}

View File

@ -0,0 +1,63 @@
/**
*
* 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.compute.internal;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.internal.TemplateBuilderImpl;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.Location;
import org.jclouds.vcloud.compute.options.VCloudTemplateOptions;
import com.google.common.base.Supplier;
/**
*
* @author Adrian Cole
*/
public class VCloudTemplateBuilderImpl extends TemplateBuilderImpl {
@Inject
protected VCloudTemplateBuilderImpl(Supplier<Set<? extends Location>> locations,
Supplier<Set<? extends Image>> images, Supplier<Set<? extends Size>> sizes,
Supplier<Location> defaultLocation, Provider<TemplateOptions> optionsProvider,
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider) {
super(locations, images, sizes, defaultLocation, optionsProvider, defaultTemplateProvider);
}
@Override
protected void copyTemplateOptions(TemplateOptions from, TemplateOptions to) {
super.copyTemplateOptions(from, to);
if (from instanceof VCloudTemplateOptions) {
VCloudTemplateOptions eFrom = VCloudTemplateOptions.class.cast(from);
VCloudTemplateOptions eTo = VCloudTemplateOptions.class.cast(to);
if (eFrom.getCustomizationScript() != null)
eTo.customizationScript(eFrom.getCustomizationScript());
}
}
}

View File

@ -0,0 +1,243 @@
/**
*
* 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.compute.options;
import java.util.Arrays;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.io.Payload;
import org.jclouds.util.Utils;
/**
* Contains options supported in the {@code ComputeService#runNode} operation on the "vcloud"
* provider. <h2>
* Usage</h2> The recommended way to instantiate a VCloudTemplateOptions object is to statically
* import VCloudTemplateOptions.* and invoke a static creation method followed by an instance
* mutator (if needed):
* <p/>
* <code>
* import static org.jclouds.compute.options.VCloudTemplateOptions.Builder.*;
* <p/>
* ComputeService client = // get connection
* templateBuilder.options(inboundPorts(22, 80, 8080, 443));
* Set<? extends NodeMetadata> set = client.runNodesWithTag(tag, 2, templateBuilder.build());
* <code>
*
* @author Adrian Cole
*/
public class VCloudTemplateOptions extends TemplateOptions {
private String customizationScript = null;
public static final VCloudTemplateOptions NONE = new VCloudTemplateOptions();
/**
* Specifies the customizationScript used to run instances with
*/
public VCloudTemplateOptions customizationScript(String customizationScript) {
Utils.checkNotEmpty(customizationScript, "customizationScript must be non-empty");
this.customizationScript = customizationScript;
return this;
}
public static class Builder {
/**
* @see VCloudTemplateOptions#customizationScript
*/
public static VCloudTemplateOptions customizationScript(String customizationScript) {
VCloudTemplateOptions options = new VCloudTemplateOptions();
return VCloudTemplateOptions.class.cast(options.customizationScript(customizationScript));
}
// methods that only facilitate returning the correct object type
/**
* @see TemplateOptions#inboundPorts
*/
public static VCloudTemplateOptions inboundPorts(int... ports) {
VCloudTemplateOptions options = new VCloudTemplateOptions();
return VCloudTemplateOptions.class.cast(options.inboundPorts(ports));
}
/**
* @see TemplateOptions#port
*/
public static VCloudTemplateOptions blockOnPort(int port, int seconds) {
VCloudTemplateOptions options = new VCloudTemplateOptions();
return VCloudTemplateOptions.class.cast(options.blockOnPort(port, seconds));
}
/**
* @see TemplateOptions#runScript
*/
public static VCloudTemplateOptions runScript(Payload script) {
VCloudTemplateOptions options = new VCloudTemplateOptions();
return VCloudTemplateOptions.class.cast(options.runScript(script));
}
/**
* @see TemplateOptions#installPrivateKey
*/
public static VCloudTemplateOptions installPrivateKey(Payload rsaKey) {
VCloudTemplateOptions options = new VCloudTemplateOptions();
return VCloudTemplateOptions.class.cast(options.installPrivateKey(rsaKey));
}
/**
* @see TemplateOptions#authorizePublicKey
*/
public static VCloudTemplateOptions authorizePublicKey(Payload rsaKey) {
VCloudTemplateOptions options = new VCloudTemplateOptions();
return VCloudTemplateOptions.class.cast(options.authorizePublicKey(rsaKey));
}
/**
* @see TemplateOptions#withDetails
*/
public static VCloudTemplateOptions withDetails() {
VCloudTemplateOptions options = new VCloudTemplateOptions();
return VCloudTemplateOptions.class.cast(options.withMetadata());
}
}
/**
* @return customizationScript on the vms
*/
public String getCustomizationScript() {
return customizationScript;
}
// methods that only facilitate returning the correct object type
/**
* @see TemplateOptions#blockOnPort
*/
@Override
public VCloudTemplateOptions blockOnPort(int port, int seconds) {
return VCloudTemplateOptions.class.cast(super.blockOnPort(port, seconds));
}
/**
*
* special thing is that we do assume if you are passing groups that you have everything you need
* already defined. for example, our option inboundPorts normally creates ingress rules
* accordingly but if we notice you've specified securityGroups, we do not mess with rules at all
*
* @see TemplateOptions#inboundPorts
*/
@Override
public VCloudTemplateOptions inboundPorts(int... ports) {
return VCloudTemplateOptions.class.cast(super.inboundPorts(ports));
}
/**
* @see TemplateOptions#authorizePublicKey(String)
*/
@Override
@Deprecated
public VCloudTemplateOptions authorizePublicKey(String publicKey) {
return VCloudTemplateOptions.class.cast(super.authorizePublicKey(publicKey));
}
/**
* @see TemplateOptions#authorizePublicKey(Payload)
*/
@Override
public VCloudTemplateOptions authorizePublicKey(Payload publicKey) {
return VCloudTemplateOptions.class.cast(super.authorizePublicKey(publicKey));
}
/**
* @see TemplateOptions#installPrivateKey(String)
*/
@Override
@Deprecated
public VCloudTemplateOptions installPrivateKey(String privateKey) {
return VCloudTemplateOptions.class.cast(super.installPrivateKey(privateKey));
}
/**
* @see TemplateOptions#installPrivateKey(Payload)
*/
@Override
public VCloudTemplateOptions installPrivateKey(Payload privateKey) {
return VCloudTemplateOptions.class.cast(super.installPrivateKey(privateKey));
}
/**
* @see TemplateOptions#runScript(Payload)
*/
@Override
public VCloudTemplateOptions runScript(Payload script) {
return VCloudTemplateOptions.class.cast(super.runScript(script));
}
/**
* @see TemplateOptions#runScript(byte[])
*/
@Override
@Deprecated
public VCloudTemplateOptions runScript(byte[] script) {
return VCloudTemplateOptions.class.cast(super.runScript(script));
}
/**
* @see TemplateOptions#withMetadata
*/
@Override
public VCloudTemplateOptions withMetadata() {
return VCloudTemplateOptions.class.cast(super.withMetadata());
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((customizationScript == null) ? 0 : customizationScript.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
VCloudTemplateOptions other = (VCloudTemplateOptions) obj;
if (customizationScript == null) {
if (other.customizationScript != null)
return false;
} else if (!customizationScript.equals(other.customizationScript))
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
+ "]";
}
}

View File

@ -35,11 +35,15 @@ import org.jclouds.compute.strategy.AddNodeWithTagStrategy;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
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.Task;
import org.jclouds.vcloud.domain.VApp;
import org.jclouds.vcloud.domain.Vm;
import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
@ -66,6 +70,17 @@ public class VCloudAddNodeWithTagStrategy implements AddNodeWithTagStrategy {
public NodeMetadata execute(String tag, String name, Template template) {
InstantiateVAppTemplateOptions options = processorCount(Double.valueOf(template.getSize().getCores()).intValue())
.memory(template.getSize().getRam()).disk(template.getSize().getDisk() * 1024 * 1024l);
String customizationScript = null;
if (template.getOptions() instanceof VCloudTemplateOptions) {
customizationScript = VCloudTemplateOptions.class.cast(template.getOptions()).getCustomizationScript();
if (customizationScript != null) {
options.customizeOnInstantiate(false);
options.deploy(false);
options.powerOn(false);
}
}
if (!template.getOptions().shouldBlockUntilRunning())
options.block(false);
@ -78,6 +93,35 @@ public class VCloudAddNodeWithTagStrategy implements AddNodeWithTagStrategy {
logger.debug("<< instantiated VApp(%s)", vAppResponse.getName());
Task task = vAppResponse.getTasks().get(0);
if (customizationScript == 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));
}
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));
}
task = client.deployAndPowerOnVAppOrVm(vAppResponse.getHref());
return blockOnDeployAndPowerOnIfConfigured(options, vAppResponse, task);
}
}
private NodeMetadata blockOnDeployAndPowerOnIfConfigured(InstantiateVAppTemplateOptions options, VApp vAppResponse,
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

View File

@ -21,30 +21,39 @@ package org.jclouds.vcloud.domain;
import java.net.URI;
import org.jclouds.vcloud.VCloudMediaType;
/**
* The GuestCustomization of a Vm contains customization parameters for the guest
* operating system of the virtual machine.
* The GuestCustomization of a Vm contains customization parameters for the guest operating system
* of the virtual machine.
*/
public class GuestCustomizationSection {
protected final String type;
protected final URI href;
protected final String info;
protected final Boolean enabled;
protected final Boolean changeSid;
protected final String virtualMachineId;
protected final Boolean joinDomainEnabled;
protected final Boolean useOrgSettings;
protected final String domainName;
protected final String domainUserName;
protected final String domainUserPassword;
protected final Boolean adminPasswordEnabled;
protected final Boolean adminPasswordAuto;
protected final String adminPassword;
protected final Boolean resetPasswordRequired;
protected final String customizationScript;
protected final String computerName;
protected String info;
protected Boolean enabled;
protected Boolean changeSid;
protected String virtualMachineId;
protected Boolean joinDomainEnabled;
protected Boolean useOrgSettings;
protected String domainName;
protected String domainUserName;
protected String domainUserPassword;
protected Boolean adminPasswordEnabled;
protected Boolean adminPasswordAuto;
protected String adminPassword;
protected Boolean resetPasswordRequired;
protected String customizationScript;
protected String computerName;
protected final ReferenceType edit;
public GuestCustomizationSection(URI href) {
this.href = href;
this.type = VCloudMediaType.GUESTCUSTOMIZATIONSECTION_XML;
this.info = "Specifies Guest OS Customization Settings";
this.edit = null;
}
public GuestCustomizationSection(String type, URI href, String info, Boolean enabled, Boolean changeSid,
String virtualMachineId, Boolean joinDomainEnabled, Boolean useOrgSettings, String domainName,
String domainUserName, String domainUserPassword, Boolean adminPasswordEnabled, Boolean adminPasswordAuto,
@ -223,7 +232,7 @@ public class GuestCustomizationSection {
@Override
public int hashCode() {
final int prime = 31;
int prime = 31;
int result = 1;
result = prime * result + ((adminPassword == null) ? 0 : adminPassword.hashCode());
result = prime * result + ((adminPasswordAuto == null) ? 0 : adminPasswordAuto.hashCode());
@ -347,4 +356,88 @@ public class GuestCustomizationSection {
return false;
return true;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Boolean getChangeSid() {
return changeSid;
}
public void setChangeSid(Boolean changeSid) {
this.changeSid = changeSid;
}
public Boolean getJoinDomainEnabled() {
return joinDomainEnabled;
}
public void setJoinDomainEnabled(Boolean joinDomainEnabled) {
this.joinDomainEnabled = joinDomainEnabled;
}
public Boolean shouldUseOrgSettings() {
return useOrgSettings;
}
public void setUseOrgSettings(Boolean useOrgSettings) {
this.useOrgSettings = useOrgSettings;
}
public Boolean getAdminPasswordEnabled() {
return adminPasswordEnabled;
}
public void setAdminPasswordEnabled(Boolean adminPasswordEnabled) {
this.adminPasswordEnabled = adminPasswordEnabled;
}
public Boolean getAdminPasswordAuto() {
return adminPasswordAuto;
}
public void setAdminPasswordAuto(Boolean adminPasswordAuto) {
this.adminPasswordAuto = adminPasswordAuto;
}
public Boolean getResetPasswordRequired() {
return resetPasswordRequired;
}
public void setResetPasswordRequired(Boolean resetPasswordRequired) {
this.resetPasswordRequired = resetPasswordRequired;
}
public void setInfo(String info) {
this.info = info;
}
public void setVirtualMachineId(String virtualMachineId) {
this.virtualMachineId = virtualMachineId;
}
public void setDomainName(String domainName) {
this.domainName = domainName;
}
public void setDomainUserName(String domainUserName) {
this.domainUserName = domainUserName;
}
public void setDomainUserPassword(String domainUserPassword) {
this.domainUserPassword = domainUserPassword;
}
public void setAdminPassword(String adminPassword) {
this.adminPassword = adminPassword;
}
public void setCustomizationScript(String customizationScript) {
this.customizationScript = customizationScript;
}
public void setComputerName(String computerName) {
this.computerName = computerName;
}
}

View File

@ -26,8 +26,6 @@ import java.util.Set;
import org.jclouds.vcloud.domain.network.NetworkConfig;
import com.google.common.collect.Sets;
/**
@ -38,6 +36,7 @@ import com.google.common.collect.Sets;
public class InstantiateVAppTemplateOptions {
private Set<NetworkConfig> networkConfig = Sets.newLinkedHashSet();
private Boolean customizeOnInstantiate;
private String cpuCount;
private String memorySizeMegabytes;
private String diskSizeKilobytes;
@ -82,6 +81,15 @@ public class InstantiateVAppTemplateOptions {
return this;
}
/**
* If true, then customization is executed for all children that include a
* GuestCustomizationSection.
*/
public InstantiateVAppTemplateOptions customizeOnInstantiate(boolean customizeOnInstantiate) {
this.customizeOnInstantiate = customizeOnInstantiate;
return this;
}
public InstantiateVAppTemplateOptions processorCount(int cpuCount) {
checkArgument(cpuCount >= 1, "cpuCount must be positive");
this.cpuCount = cpuCount + "";
@ -126,6 +134,10 @@ public class InstantiateVAppTemplateOptions {
return cpuCount;
}
public Boolean shouldCustomizeOnInstantiate() {
return customizeOnInstantiate;
}
public String getMemorySizeMegabytes() {
return memorySizeMegabytes;
}
@ -168,6 +180,14 @@ public class InstantiateVAppTemplateOptions {
return options.processorCount(cpuCount);
}
/**
* @see InstantiateVAppTemplateOptions#customizeOnInstantiate
*/
public static InstantiateVAppTemplateOptions customizeOnInstantiate(Boolean customizeOnInstantiate) {
InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions();
return options.customizeOnInstantiate(customizeOnInstantiate);
}
/**
* @see InstantiateVAppTemplateOptions#memory(int)
*/
@ -197,7 +217,9 @@ public class InstantiateVAppTemplateOptions {
@Override
public String toString() {
return "InstantiateVAppTemplateOptions [cpuCount=" + cpuCount + ", memorySizeMegabytes=" + memorySizeMegabytes
+ ", diskSizeKilobytes=" + diskSizeKilobytes + ", networkConfig=" + networkConfig + "]";
+ ", diskSizeKilobytes=" + diskSizeKilobytes + ", networkConfig=" + networkConfig
+ ", customizeOnInstantiate=" + customizeOnInstantiate + ", deploy=" + (deploy) + ", powerOn="
+ (powerOn) + "]";
}
@Override
@ -206,10 +228,11 @@ public class InstantiateVAppTemplateOptions {
int result = 1;
result = prime * result + (block ? 1231 : 1237);
result = prime * result + ((cpuCount == null) ? 0 : cpuCount.hashCode());
result = prime * result + ((customizeOnInstantiate == null) ? 0 : customizeOnInstantiate.hashCode());
result = prime * result + (deploy ? 1231 : 1237);
result = prime * result + ((diskSizeKilobytes == null) ? 0 : diskSizeKilobytes.hashCode());
result = prime * result + ((networkConfig == null) ? 0 : networkConfig.hashCode());
result = prime * result + ((memorySizeMegabytes == null) ? 0 : memorySizeMegabytes.hashCode());
result = prime * result + ((networkConfig == null) ? 0 : networkConfig.hashCode());
result = prime * result + (powerOn ? 1231 : 1237);
return result;
}
@ -230,6 +253,11 @@ public class InstantiateVAppTemplateOptions {
return false;
} else if (!cpuCount.equals(other.cpuCount))
return false;
if (customizeOnInstantiate == null) {
if (other.customizeOnInstantiate != null)
return false;
} else if (!customizeOnInstantiate.equals(other.customizeOnInstantiate))
return false;
if (deploy != other.deploy)
return false;
if (diskSizeKilobytes == null) {
@ -237,16 +265,16 @@ public class InstantiateVAppTemplateOptions {
return false;
} else if (!diskSizeKilobytes.equals(other.diskSizeKilobytes))
return false;
if (networkConfig == null) {
if (other.networkConfig != null)
return false;
} else if (!networkConfig.equals(other.networkConfig))
return false;
if (memorySizeMegabytes == null) {
if (other.memorySizeMegabytes != null)
return false;
} else if (!memorySizeMegabytes.equals(other.memorySizeMegabytes))
return false;
if (networkConfig == null) {
if (other.networkConfig != null)
return false;
} else if (!networkConfig.equals(other.networkConfig))
return false;
if (powerOn != other.powerOn)
return false;
return true;

View File

@ -118,6 +118,9 @@ public class GuestCustomizationSectionHandler extends ParseSax.HandlerWithResult
this.resetPasswordRequired = Boolean.parseBoolean(currentOrNull());
} else if (qName.endsWith("CustomizationScript")) {
this.customizationScript = currentOrNull();
if (this.customizationScript != null)
customizationScript = customizationScript.replace("&lt;", "<").replace(">", "&gt;").replace("&quot;", "\"")
.replace("&apos;", "'").replace("&#13;", "\r\n").replace("&#13;", "\n").replace("&amp;", "&");
} else if (qName.endsWith("ComputerName")) {
this.computerName = currentOrNull();
} else if (qName.endsWith("Name")) {

View File

@ -51,6 +51,7 @@ import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.util.Utils;
import org.jclouds.vcloud.config.VCloudRestClientModule;
import org.jclouds.vcloud.domain.GuestCustomizationSection;
import org.jclouds.vcloud.domain.Org;
import org.jclouds.vcloud.domain.ReferenceType;
import org.jclouds.vcloud.domain.Task;
@ -97,6 +98,28 @@ import domain.VCloudVersionsAsyncClient;
*/
@Test(groups = "unit", testName = "vcloud.VCloudAsyncClientTest")
public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
public void testUpdateGuestConfiguration() throws SecurityException, NoSuchMethodException, IOException {
Method method = VCloudAsyncClient.class.getMethod("updateGuestCustomizationOfVm", URI.class,
GuestCustomizationSection.class);
GuestCustomizationSection guest = new GuestCustomizationSection(URI
.create("http://vcloud.example.com/api/v1.0/vApp/vm-12/guestCustomizationSection"));
guest.setCustomizationScript("cat > /tmp/foo.txt<<EOF\nI love candy\nEOF");
HttpRequest request = processor.createRequest(method,
URI.create("http://vcloud.example.com/api/v1.0/vApp/vm-12"), guest);
assertRequestLineEquals(request,
"PUT http://vcloud.example.com/api/v1.0/vApp/vm-12/guestCustomizationSection HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Accept: application/vnd.vmware.vcloud.task+xml\n");
assertPayloadEquals(request, Utils.toStringAndClose(getClass().getResourceAsStream(
"/guestCustomizationSection.xml")), "application/vnd.vmware.vcloud.guestCustomizationSection+xml",
false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, TaskHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
public void testInstantiateVAppTemplateInVDCURIOptions() throws SecurityException, NoSuchMethodException,
IOException {
@ -127,11 +150,11 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
IOException {
Method method = VCloudAsyncClient.class.getMethod("instantiateVAppTemplateInVDC", URI.class, URI.class,
String.class, InstantiateVAppTemplateOptions[].class);
processor
.createRequest(method, URI.create("https://vcenterprise.bluelock.com/api/v1.0/vdc/1"), URI
.create("https://vcenterprise.bluelock.com/api/v1.0/vdc/1"), "CentOS 01", processorCount(1).memory(
512).disk(1024).addNetworkConfig(
new NetworkConfig(null, URI.create("https://vcenterprise.bluelock.com/api/v1.0/network/1991"), null)));
processor.createRequest(method, URI.create("https://vcenterprise.bluelock.com/api/v1.0/vdc/1"), URI
.create("https://vcenterprise.bluelock.com/api/v1.0/vdc/1"), "CentOS 01", processorCount(1).memory(512)
.disk(1024).addNetworkConfig(
new NetworkConfig(null, URI.create("https://vcenterprise.bluelock.com/api/v1.0/network/1991"),
null)));
}
public void testCloneVAppInVDC() throws SecurityException, NoSuchMethodException, IOException {
@ -159,8 +182,8 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
CloneVAppOptions[].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"), "new-linux-server", new CloneVAppOptions()
.deploy().powerOn().withDescription("The description of the new vApp"));
.create("https://vcenterprise.bluelock.com/api/v1.0/vapp/201"), "new-linux-server",
new CloneVAppOptions().deploy().powerOn().withDescription("The description of the new vApp"));
assertRequestLineEquals(request,
"POST https://vcenterprise.bluelock.com/api/v1.0/vdc/1/action/cloneVApp HTTP/1.1");
@ -807,17 +830,42 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
protected Supplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.VDC>>> provideOrgVDCSupplierCache(
@Named(PROPERTY_SESSION_INTERVAL) long seconds, final OrgVDCSupplier supplier) {
return Suppliers.<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.VDC>>> ofInstance(ImmutableMap
.<String, Map<String, ? extends org.jclouds.vcloud.domain.VDC>> of("org",
return Suppliers
.<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.VDC>>> ofInstance(ImmutableMap
.<String, Map<String, ? extends org.jclouds.vcloud.domain.VDC>> of(
"org",
ImmutableMap.<String, org.jclouds.vcloud.domain.VDC> of("vdc", new VDCImpl("vdc", null, URI
.create("https://vcenterprise.bluelock.com/api/v1.0/vdc/1"), null, null, "description", null,
null, null, null, null, ImmutableMap.<String, ReferenceType> of("vapp", new ReferenceTypeImpl(
"vapp", "application/vnd.vmware.vcloud.vApp+xml", URI
.create("https://vcenterprise.bluelock.com/api/v1.0/vApp/188849-1")), "network",
new ReferenceTypeImpl("network", "application/vnd.vmware.vcloud.vAppTemplate+xml", URI
.create("https://vcenterprise.bluelock.com/api/v1.0/vdcItem/2"))), null, 0, 0, 0,
false))));
ImmutableMap
.<String, org.jclouds.vcloud.domain.VDC> of(
"vdc",
new VDCImpl(
"vdc",
null,
URI
.create("https://vcenterprise.bluelock.com/api/v1.0/vdc/1"),
null,
null,
"description",
null,
null,
null,
null,
null,
ImmutableMap
.<String, ReferenceType> of(
"vapp",
new ReferenceTypeImpl(
"vapp",
"application/vnd.vmware.vcloud.vApp+xml",
URI
.create("https://vcenterprise.bluelock.com/api/v1.0/vApp/188849-1")),
"network",
new ReferenceTypeImpl(
"network",
"application/vnd.vmware.vcloud.vAppTemplate+xml",
URI
.create("https://vcenterprise.bluelock.com/api/v1.0/vdcItem/2"))),
null, 0, 0, 0, false))));
}
@ -832,14 +880,17 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
public Map<String, Org> get() {
return ImmutableMap.<String, Org> of("org", new OrgImpl("org", null, URI
.create("https://vcenterprise.bluelock.com/api/v1.0/org/1"), "org", "description", ImmutableMap
.<String, ReferenceType> of("catalog", new ReferenceTypeImpl("catalog", VCloudMediaType.CATALOG_XML,
URI.create("https://vcenterprise.bluelock.com/api/v1.0/catalog/1"))), ImmutableMap
.<String, ReferenceType> of("catalog", new ReferenceTypeImpl("catalog",
VCloudMediaType.CATALOG_XML, URI
.create("https://vcenterprise.bluelock.com/api/v1.0/catalog/1"))), ImmutableMap
.<String, ReferenceType> of("vdc", new ReferenceTypeImpl("vdc", VCloudMediaType.VDC_XML, URI
.create("https://vcenterprise.bluelock.com/api/v1.0/vdc/1"))), ImmutableMap
.<String, ReferenceType> of("network", new ReferenceTypeImpl("network", VCloudMediaType.NETWORK_XML,
URI.create("https://vcenterprise.bluelock.com/api/v1.0/network/1"))), new ReferenceTypeImpl(
"tasksList", VCloudMediaType.TASKSLIST_XML, URI
.create("https://vcenterprise.bluelock.com/api/v1.0/tasksList/1")), ImmutableList.<Task> of()));
.<String, ReferenceType> of("network", new ReferenceTypeImpl("network",
VCloudMediaType.NETWORK_XML, URI
.create("https://vcenterprise.bluelock.com/api/v1.0/network/1"))),
new ReferenceTypeImpl("tasksList", VCloudMediaType.TASKSLIST_XML, URI
.create("https://vcenterprise.bluelock.com/api/v1.0/tasksList/1")), ImmutableList
.<Task> of()));
}
}
@ -855,11 +906,12 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
return ImmutableMap.<String, Map<String, ? extends org.jclouds.vcloud.domain.Catalog>> of("org",
ImmutableMap.<String, org.jclouds.vcloud.domain.Catalog> of("catalog", new CatalogImpl("catalog", "type",
URI.create("https://vcenterprise.bluelock.com/api/v1.0/catalog/1"), null, "description", ImmutableMap
.<String, ReferenceType> of("item", new ReferenceTypeImpl("item",
URI.create("https://vcenterprise.bluelock.com/api/v1.0/catalog/1"), null, "description",
ImmutableMap.<String, ReferenceType> of("item", new ReferenceTypeImpl("item",
"application/vnd.vmware.vcloud.catalogItem+xml", URI
.create("https://vcenterprise.bluelock.com/api/v1.0/catalogItem/1")), "template",
new ReferenceTypeImpl("template", "application/vnd.vmware.vcloud.vAppTemplate+xml", URI
.create("https://vcenterprise.bluelock.com/api/v1.0/catalogItem/1")),
"template", new ReferenceTypeImpl("template",
"application/vnd.vmware.vcloud.vAppTemplate+xml", URI
.create("https://vcenterprise.bluelock.com/api/v1.0/catalogItem/2"))),
ImmutableList.<Task> of(), true)));
}
@ -873,13 +925,25 @@ public class VCloudAsyncClientTest extends RestClientTest<VCloudAsyncClient> {
@Override
public Map<String, Map<String, Map<String, ? extends org.jclouds.vcloud.domain.CatalogItem>>> get() {
return ImmutableMap.<String, Map<String, Map<String, ? extends org.jclouds.vcloud.domain.CatalogItem>>> of(
"org", ImmutableMap.<String, Map<String, ? extends org.jclouds.vcloud.domain.CatalogItem>> of(
"catalog", ImmutableMap.<String, org.jclouds.vcloud.domain.CatalogItem> of("template",
new CatalogItemImpl("template", URI
.create("https://vcenterprise.bluelock.com/api/v1.0/catalogItem/2"), "description",
new ReferenceTypeImpl("template", "application/vnd.vmware.vcloud.vAppTemplate+xml",
URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/2")),
return ImmutableMap
.<String, Map<String, Map<String, ? extends org.jclouds.vcloud.domain.CatalogItem>>> of(
"org",
ImmutableMap
.<String, Map<String, ? extends org.jclouds.vcloud.domain.CatalogItem>> of(
"catalog",
ImmutableMap
.<String, org.jclouds.vcloud.domain.CatalogItem> of(
"template",
new CatalogItemImpl(
"template",
URI
.create("https://vcenterprise.bluelock.com/api/v1.0/catalogItem/2"),
"description",
new ReferenceTypeImpl(
"template",
"application/vnd.vmware.vcloud.vAppTemplate+xml",
URI
.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/2")),
ImmutableMap.<String, String> of()))));
}

View File

@ -0,0 +1,143 @@
/**
*
* 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.get;
import static org.testng.Assert.assertEquals;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.Constants;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ComputeServiceContextFactory;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.net.IPSocket;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.predicates.SocketOpen;
import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshClient.Factory;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.jclouds.vcloud.compute.options.VCloudTemplateOptions;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
*
*
* @author Adrian Cole
*/
@Test(groups = "live", enabled = true, sequential = true, testName = "vcloud.VCloudGuestCustomizationLiveTest")
public class VCloudGuestCustomizationLiveTest {
protected String identity;
protected String provider;
protected String credential;
protected ComputeServiceContext context;
protected ComputeService client;
protected RetryablePredicate<IPSocket> socketTester;
protected Factory sshFactory;
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");
context = new ComputeServiceContextFactory().createContext(provider, identity, credential, ImmutableSet
.<Module> of(new Log4JLoggingModule()), props);
client = context.getComputeService();
Injector injector = createSshClientInjector();
sshFactory = injector.getInstance(SshClient.Factory.class);
SocketOpen socketOpen = injector.getInstance(SocketOpen.class);
socketTester = new RetryablePredicate<IPSocket>(socketOpen, 60, 1, TimeUnit.SECONDS);
injector.injectMembers(socketOpen); // add logger
}
protected Injector createSshClientInjector() {
return Guice.createInjector(getSshModule());
}
protected JschSshClientModule getSshModule() {
return new JschSshClientModule();
}
@Test
public void testExtendedOptionsWithCustomizationScript() throws Exception {
String tag = "customize";
TemplateOptions options = client.templateOptions();
options.as(VCloudTemplateOptions.class).customizationScript("cat > /root/foo.txt<<EOF\nI love candy\nEOF\n");
String nodeId = null;
try {
Set<? extends NodeMetadata> nodes = client.runNodesWithTag(tag, 1, options);
NodeMetadata node = Iterables.get(nodes, 0);
nodeId = node.getId();
IPSocket socket = new IPSocket(get(node.getPublicAddresses(), 0), 22);
socketTester.apply(socket);
SshClient ssh = sshFactory.create(socket, node.getCredentials().identity, node.getCredentials().credential);
try {
ssh.connect();
System.out
.println(ssh
.exec("vmtoolsd --cmd=\"info-get guestinfo.ovfenv\" |grep vCloud_CustomizationInfo|sed 's/.*value=\"\\(.*\\)\".*/\\1/g'|base64 -d"));
ExecResponse hello = ssh.exec("cat /root/foo.txt");
assertEquals(hello.getOutput().trim(), "I love candy");
} finally {
if (ssh != null)
ssh.disconnect();
}
} finally {
if (nodeId != null)
client.destroyNode(nodeId);
}
}
}

View File

@ -25,6 +25,7 @@ import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig;
import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.customizeOnInstantiate;
import java.io.IOException;
import java.net.URI;
@ -196,6 +197,46 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest {
binder.bindToRequest(request, map);
verify(request);
}
public void testWithCustomization() throws IOException {
URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
VAppTemplate template = createMock(VAppTemplate.class);
VCloudNetworkSection net = createMock(VCloudNetworkSection.class);
InstantiateVAppTemplateOptions options = customizeOnInstantiate(true);
String expected = Utils
.toStringAndClose(getClass().getResourceAsStream("/instantiationparams-customization.xml"));
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();
expect(request.getArgs()).andReturn(new Object[] { options }).atLeastOnce();
request.setPayload(expected);
expect(template.getNetworkSection()).andReturn(net).atLeastOnce();
expect(net.getNetworks())
.andReturn(
ImmutableSet
.<org.jclouds.vcloud.domain.ovf.network.Network> of(new org.jclouds.vcloud.domain.ovf.network.Network(
"vAppNet-vApp Internal", null)));
replay(request);
replay(template);
replay(net);
BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance(
BindInstantiateVAppTemplateParamsToXmlPayload.class);
Map<String, String> map = Maps.newHashMap();
map.put("name", "my-vapp");
map.put("template", "https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3");
binder.bindToRequest(request, map);
verify(request);
verify(template);
verify(net);
}
}

View File

@ -76,5 +76,4 @@ public class VCloudComputeServiceLiveTest extends BaseComputeServiceLiveTest {
System.out.println(allData.getExtra());
}
}
}

View File

@ -0,0 +1,182 @@
/**
*
* 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.compute.options;
import static org.jclouds.vcloud.compute.options.VCloudTemplateOptions.Builder.authorizePublicKey;
import static org.jclouds.vcloud.compute.options.VCloudTemplateOptions.Builder.blockOnPort;
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.testng.Assert.assertEquals;
import java.io.IOException;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.io.Payloads;
import org.jclouds.util.Utils;
import org.testng.annotations.Test;
/**
* Tests possible uses of VCloudTemplateOptions and VCloudTemplateOptions.Builder.*
*
* @author Adrian Cole
*/
public class VCloudTemplateOptionsTest {
public void testAs() {
TemplateOptions options = new VCloudTemplateOptions();
assertEquals(options.as(VCloudTemplateOptions.class), options);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testcustomizationScriptBadFormat() {
VCloudTemplateOptions options = new VCloudTemplateOptions();
options.customizationScript("");
}
@Test
public void testcustomizationScript() {
VCloudTemplateOptions options = new VCloudTemplateOptions();
options.customizationScript("mykeypair");
assertEquals(options.getCustomizationScript(), "mykeypair");
}
@Test
public void testNullcustomizationScript() {
VCloudTemplateOptions options = new VCloudTemplateOptions();
assertEquals(options.getCustomizationScript(), null);
}
@Test
public void testcustomizationScriptStatic() {
VCloudTemplateOptions options = customizationScript("mykeypair");
assertEquals(options.getCustomizationScript(), "mykeypair");
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testcustomizationScriptNPE() {
customizationScript(null);
}
@Test
public void testinstallPrivateKey() throws IOException {
VCloudTemplateOptions options = new VCloudTemplateOptions();
options.installPrivateKey(Payloads.newPayload("-----BEGIN RSA PRIVATE KEY-----"));
assertEquals(Utils.toStringAndClose(options.getPrivateKey().getInput()), "-----BEGIN RSA PRIVATE KEY-----");
}
@Test
public void testNullinstallPrivateKey() {
VCloudTemplateOptions options = new VCloudTemplateOptions();
assertEquals(options.getPrivateKey(), null);
}
@Test
public void testinstallPrivateKeyStatic() throws IOException {
VCloudTemplateOptions options = installPrivateKey(Payloads.newPayload("-----BEGIN RSA PRIVATE KEY-----"));
assertEquals(Utils.toStringAndClose(options.getPrivateKey().getInput()), "-----BEGIN RSA PRIVATE KEY-----");
}
@Test(expectedExceptions = NullPointerException.class)
public void testinstallPrivateKeyNPE() {
installPrivateKey(null);
}
@Test
public void testauthorizePublicKey() throws IOException {
VCloudTemplateOptions options = new VCloudTemplateOptions();
options.authorizePublicKey(Payloads.newPayload("ssh-rsa"));
assertEquals(Utils.toStringAndClose(options.getPublicKey().getInput()), "ssh-rsa");
}
@Test
public void testNullauthorizePublicKey() {
VCloudTemplateOptions options = new VCloudTemplateOptions();
assertEquals(options.getPublicKey(), null);
}
@Test
public void testauthorizePublicKeyStatic() throws IOException {
VCloudTemplateOptions options = authorizePublicKey(Payloads.newPayload("ssh-rsa"));
assertEquals(Utils.toStringAndClose(options.getPublicKey().getInput()), "ssh-rsa");
}
@Test(expectedExceptions = NullPointerException.class)
public void testauthorizePublicKeyNPE() {
authorizePublicKey(null);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testblockOnPortBadFormat() {
VCloudTemplateOptions options = new VCloudTemplateOptions();
options.blockOnPort(-1, -1);
}
@Test
public void testblockOnPort() {
VCloudTemplateOptions options = new VCloudTemplateOptions();
options.blockOnPort(22, 30);
assertEquals(options.getPort(), 22);
assertEquals(options.getSeconds(), 30);
}
@Test
public void testNullblockOnPort() {
VCloudTemplateOptions options = new VCloudTemplateOptions();
assertEquals(options.getPort(), -1);
assertEquals(options.getSeconds(), -1);
}
@Test
public void testblockOnPortStatic() {
VCloudTemplateOptions options = blockOnPort(22, 30);
assertEquals(options.getPort(), 22);
assertEquals(options.getSeconds(), 30);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testinboundPortsBadFormat() {
VCloudTemplateOptions options = new VCloudTemplateOptions();
options.inboundPorts(-1, -1);
}
@Test
public void testinboundPorts() {
VCloudTemplateOptions options = new VCloudTemplateOptions();
options.inboundPorts(22, 30);
assertEquals(options.getInboundPorts()[0], 22);
assertEquals(options.getInboundPorts()[1], 30);
}
@Test
public void testDefaultOpen22() {
VCloudTemplateOptions options = new VCloudTemplateOptions();
assertEquals(options.getInboundPorts()[0], 22);
}
@Test
public void testinboundPortsStatic() {
VCloudTemplateOptions options = inboundPorts(22, 30);
assertEquals(options.getInboundPorts()[0], 22);
assertEquals(options.getInboundPorts()[1], 30);
}
}

View File

@ -20,6 +20,7 @@
package org.jclouds.vcloud.options;
import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig;
import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.customizeOnInstantiate;
import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.disk;
import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.memory;
import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.processorCount;
@ -77,6 +78,19 @@ public class InstantiateVAppTemplateOptionsTest {
assertEquals(options.getCpuCount(), "3");
}
@Test
public void testCustomizeOnInstantiate() {
InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions();
options.customizeOnInstantiate(true);
assertEquals(options.shouldCustomizeOnInstantiate(), new Boolean(true));
}
@Test
public void testCustomizeOnInstantiateStatic() {
InstantiateVAppTemplateOptions options = customizeOnInstantiate(true);
assertEquals(options.shouldCustomizeOnInstantiate(), new Boolean(true));
}
@Test
public void testRam() {
InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions();

View File

@ -0,0 +1,3 @@
<GuestCustomizationSection xmlns="http://www.vmware.com/vcloud/v1" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" href="http://vcloud.example.com/api/v1.0/vApp/vm-12/guestCustomizationSection" ovf:required="false" type="application/vnd.vmware.vcloud.guestCustomizationSection+xml"><ovf:Info>Specifies Guest OS Customization Settings</ovf:Info><CustomizationScript>cat &gt; /tmp/foo.txt&lt;&lt;EOF
I love candy
EOF</CustomizationScript></GuestCustomizationSection>

View File

@ -0,0 +1 @@
<InstantiateVAppTemplateParams xmlns="http://www.vmware.com/vcloud/v1" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" deploy="true" name="my-vapp" powerOn="true"><InstantiationParams><NetworkConfigSection><ovf:Info>Configuration parameters for logical networks</ovf:Info><NetworkConfig networkName="vAppNet-vApp Internal"><Configuration><ParentNetwork href="https://vcenterprise.bluelock.com/api/v1.0/network/1990"/><FenceMode>bridged</FenceMode></Configuration></NetworkConfig></NetworkConfigSection></InstantiationParams><Source href="https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"/><AllEULAsAccepted>true</AllEULAsAccepted></InstantiateVAppTemplateParams>