diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskInErrorStateException.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskInErrorStateException.java new file mode 100644 index 0000000000..94908a3c92 --- /dev/null +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskInErrorStateException.java @@ -0,0 +1,43 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you 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 org.jclouds.vcloud.domain.Task; + +/** + * + * @author Adrian Cole + * + */ +public class TaskInErrorStateException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private final Task task; + + public TaskInErrorStateException(Task task) { + super("error on task: " + task + " error: " + task.getError()); + this.task = task; + } + + public Task getTask() { + return task; + } + +} diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskStillRunningException.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskStillRunningException.java new file mode 100644 index 0000000000..c0b47743bc --- /dev/null +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/TaskStillRunningException.java @@ -0,0 +1,43 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you 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 org.jclouds.vcloud.domain.Task; + +/** + * + * @author Adrian Cole + * + */ +public class TaskStillRunningException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private final Task task; + + public TaskStillRunningException(Task task) { + super("task still running: " + task); + this.task = task; + } + + public Task getTask() { + return task; + } + +} diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java index 9c531a9769..a6aebc28e7 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayload.java @@ -21,7 +21,7 @@ package org.jclouds.vcloud.binders; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; -import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE; +import static com.google.common.collect.Iterables.transform; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA; @@ -30,8 +30,7 @@ import java.util.Map; import java.util.Properties; import java.util.Set; -import org.jclouds.javax.annotation.Nullable; -import javax.annotation.Resource; +import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import javax.xml.parsers.FactoryConfigurationError; @@ -39,11 +38,10 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.jclouds.http.HttpRequest; -import org.jclouds.logging.Logger; +import org.jclouds.javax.annotation.Nullable; import org.jclouds.rest.MapBinder; import org.jclouds.rest.binders.BindToStringPayload; import org.jclouds.rest.internal.GeneratedHttpRequest; -import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.domain.Vm; @@ -54,10 +52,8 @@ import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; +import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Sets; -import com.google.inject.Inject; import com.jamesmurty.utils.XMLBuilder; /** @@ -73,21 +69,21 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder protected final BindToStringPayload stringBinder; protected final ReferenceType defaultNetwork; protected final FenceMode defaultFenceMode; - protected final DefaultNetworkNameInTemplate defaultNetworkNameInTemplate; - protected final VCloudClient client; + protected final LoadingCache templateCache; + protected final Function defaultNetworkNameInTemplate; @Inject - public BindInstantiateVAppTemplateParamsToXmlPayload(DefaultNetworkNameInTemplate defaultNetworkNameInTemplate, - BindToStringPayload stringBinder, @Named(PROPERTY_VCLOUD_XML_NAMESPACE) String ns, - @Named(PROPERTY_VCLOUD_XML_SCHEMA) String schema, @Network ReferenceType network, - @Named(PROPERTY_VCLOUD_DEFAULT_FENCEMODE) String fenceMode, VCloudClient client) { + public BindInstantiateVAppTemplateParamsToXmlPayload(LoadingCache templateCache, + @Network Function defaultNetworkNameInTemplate, BindToStringPayload stringBinder, + @Named(PROPERTY_VCLOUD_XML_NAMESPACE) String ns, @Named(PROPERTY_VCLOUD_XML_SCHEMA) String schema, + @Network ReferenceType network, FenceMode fenceMode) { + this.templateCache = templateCache; this.defaultNetworkNameInTemplate = defaultNetworkNameInTemplate; this.ns = ns; this.schema = schema; this.stringBinder = stringBinder; this.defaultNetwork = network; - this.defaultFenceMode = FenceMode.fromValue(fenceMode); - this.client = client; + this.defaultFenceMode = fenceMode; } @Override @@ -97,33 +93,29 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request; checkState(gRequest.getArgs() != null, "args should be initialized at this point"); String name = checkNotNull(postParams.remove("name"), "name"); - final URI template = URI.create(checkNotNull(postParams.remove("template"), "template")); - - boolean deploy = true; - boolean powerOn = true; + URI template = URI.create(checkNotNull(postParams.remove("template"), "template")); Set networkConfig = null; - NetworkConfigDecorator networknetworkConfigDecorator = new NetworkConfigDecorator(template, + NetworkConfigDecorator networkConfigDecorator = new NetworkConfigDecorator(templateCache.getUnchecked(template), defaultNetwork.getHref(), defaultFenceMode, defaultNetworkNameInTemplate); InstantiateVAppTemplateOptions options = findOptionsInArgsOrNull(gRequest); if (options != null) { if (options.getNetworkConfig().size() > 0) - networkConfig = Sets.newLinkedHashSet(Iterables.transform(options.getNetworkConfig(), - networknetworkConfigDecorator)); - deploy = ifNullDefaultTo(options.shouldDeploy(), deploy); - powerOn = ifNullDefaultTo(options.shouldPowerOn(), powerOn); + networkConfig = ImmutableSet + .copyOf(transform(options.getNetworkConfig(), networkConfigDecorator)); + } else { + options = new InstantiateVAppTemplateOptions(); } if (networkConfig == null) - networkConfig = ImmutableSet.of(networknetworkConfigDecorator.apply(null)); + networkConfig = ImmutableSet.of(networkConfigDecorator.apply(null)); try { - return stringBinder.bindToRequest( - request, - generateXml(name, options.getDescription(), deploy, powerOn, template, networkConfig)); + return stringBinder.bindToRequest(request, generateXml(name, options.getDescription(), options.shouldDeploy(), + options.shouldPowerOn(), template, networkConfig)); } catch (ParserConfigurationException e) { throw new RuntimeException(e); } catch (FactoryConfigurationError e) { @@ -136,9 +128,9 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder @VisibleForTesting Set ifCustomizationScriptIsSetGetVmsInTemplate(String customizationScript, final URI template) { - Set vms = Sets.newLinkedHashSet(); + Set vms = ImmutableSet.of(); if (customizationScript != null) { - VAppTemplate vAppTemplate = client.getVAppTemplateClient().getVAppTemplate(template); + VAppTemplate vAppTemplate = templateCache.getUnchecked(template); checkArgument(vAppTemplate != null, "vAppTemplate %s not found!", template); vms = vAppTemplate.getChildren(); checkArgument(vms.size() > 0, "no vms found in vAppTemplate %s", vAppTemplate); @@ -147,13 +139,13 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder } protected static final class NetworkConfigDecorator implements Function { - private final URI template; + private final VAppTemplate template; private final URI defaultNetwork; private final FenceMode defaultFenceMode; - private final DefaultNetworkNameInTemplate defaultNetworkNameInTemplate; + private final Function defaultNetworkNameInTemplate; - protected NetworkConfigDecorator(URI template, URI defaultNetwork, FenceMode defaultFenceMode, - DefaultNetworkNameInTemplate defaultNetworkNameInTemplate) { + protected NetworkConfigDecorator(VAppTemplate template, URI defaultNetwork, FenceMode defaultFenceMode, + Function defaultNetworkNameInTemplate) { this.template = checkNotNull(template, "template"); this.defaultNetwork = checkNotNull(defaultNetwork, "defaultNetwork"); this.defaultFenceMode = checkNotNull(defaultFenceMode, "defaultFenceMode"); @@ -166,38 +158,14 @@ public class BindInstantiateVAppTemplateParamsToXmlPayload implements MapBinder return new NetworkConfig(defaultNetworkNameInTemplate.apply(template), defaultNetwork, defaultFenceMode); URI network = ifNullDefaultTo(from.getParentNetwork(), defaultNetwork); FenceMode fenceMode = ifNullDefaultTo(from.getFenceMode(), defaultFenceMode); + // using conditional statement instead of ifNullDefaultTo so that we lazy invoke the + // function, as it is an expensive one. String networkName = from.getNetworkName() != null ? from.getNetworkName() : defaultNetworkNameInTemplate - .apply(template); + .apply(template); return new NetworkConfig(networkName, network, fenceMode); } } - @Singleton - public static class DefaultNetworkNameInTemplate implements Function { - @Resource - protected Logger logger = Logger.NULL; - - private final VCloudClient client; - - @Inject - DefaultNetworkNameInTemplate(VCloudClient client) { - this.client = client; - } - - @Override - public String apply(URI template) { - String networkName; - VAppTemplate vAppTemplate = client.getVAppTemplateClient().getVAppTemplate(template); - checkArgument(vAppTemplate != null, "vAppTemplate %s not found!", template); - Set networks = vAppTemplate.getNetworkSection().getNetworks(); - checkArgument(networks.size() > 0, "no networks found in vAppTemplate %s", vAppTemplate); - if (networks.size() > 1) - logger.warn("multiple networks found for %s, choosing first from: %s", vAppTemplate.getName(), networks); - networkName = Iterables.get(networks, 0).getName(); - return networkName; - } - } - protected String generateXml(String name, @Nullable String description, boolean deploy, boolean powerOn, URI template, Iterable networkConfig) throws ParserConfigurationException, FactoryConfigurationError, TransformerException { diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceDependenciesModule.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceDependenciesModule.java index 31984337e0..c77c3fb717 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceDependenciesModule.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceDependenciesModule.java @@ -45,9 +45,13 @@ import org.jclouds.vcloud.compute.internal.VCloudTemplateBuilderImpl; import org.jclouds.vcloud.compute.options.VCloudTemplateOptions; import org.jclouds.vcloud.compute.strategy.VCloudComputeServiceAdapter; import org.jclouds.vcloud.domain.Org; +import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.Status; import org.jclouds.vcloud.domain.VApp; import org.jclouds.vcloud.domain.VAppTemplate; +import org.jclouds.vcloud.domain.network.FenceMode; +import org.jclouds.vcloud.domain.network.NetworkConfig; +import org.jclouds.vcloud.endpoints.Network; import org.jclouds.vcloud.functions.VAppTemplatesInOrg; import com.google.common.annotations.VisibleForTesting; @@ -110,6 +114,14 @@ public class VCloudComputeServiceDependenciesModule extends AbstractModule { }).to((Class) IdentityFunction.class); } + + @Provides + @Singleton + public NetworkConfig networkConfig(@Network ReferenceType network, FenceMode defaultFenceMode) { + return new NetworkConfig(network.getName(), network.getHref(), defaultFenceMode); + } + + @Singleton public static class DefaultVDC implements Supplier { private final Supplier> locationsSupplier; diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java index 0984e0c9da..ac14181132 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/HardwareForVAppTemplate.java @@ -30,7 +30,6 @@ import org.jclouds.compute.predicates.ImagePredicates; import org.jclouds.logging.Logger; import org.jclouds.ovf.Envelope; import org.jclouds.ovf.VirtualHardwareSection; -import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.domain.VAppTemplate; import com.google.common.base.Function; @@ -45,37 +44,25 @@ public class HardwareForVAppTemplate implements Function @Resource protected Logger logger = Logger.NULL; - private final VCloudClient client; + private final Function templateToEnvelope; private final FindLocationForResource findLocationForResource; private final VCloudHardwareBuilderFromResourceAllocations rasdToHardwareBuilder; @Inject - protected HardwareForVAppTemplate(VCloudClient client, FindLocationForResource findLocationForResource, + protected HardwareForVAppTemplate(Function templateToEnvelope, + FindLocationForResource findLocationForResource, VCloudHardwareBuilderFromResourceAllocations rasdToHardwareBuilder) { - this.client = checkNotNull(client, "client"); + this.templateToEnvelope = checkNotNull(templateToEnvelope, "templateToEnvelope"); this.findLocationForResource = checkNotNull(findLocationForResource, "findLocationForResource"); this.rasdToHardwareBuilder = checkNotNull(rasdToHardwareBuilder, "rasdToHardwareBuilder"); } - @Override public Hardware apply(VAppTemplate from) { checkNotNull(from, "VAppTemplate"); - if (!from.isOvfDescriptorUploaded()) { - logger.warn("cannot parse hardware as ovf descriptor for %s is not uploaded", from); - return null; - } + Envelope ovf = templateToEnvelope.apply(from); - Envelope ovf = client.getVAppTemplateClient().getOvfEnvelopeForVAppTemplate(from.getHref()); - if (ovf == null) { - logger.warn("cannot parse hardware as no ovf envelope found for %s", from); - return null; - } - if (ovf.getVirtualSystem().getVirtualHardwareSections().size() == 0) { - logger.warn("cannot parse hardware for %s as no hardware sections exist in ovf %s", ovf); - return null; - } if (ovf.getVirtualSystem().getVirtualHardwareSections().size() > 1) { logger.warn("multiple hardware choices found. using first", ovf); } @@ -89,6 +76,7 @@ public class HardwareForVAppTemplate implements Function builder.ids(from.getHref().toASCIIString()).name(from.getName()).supportsImage( ImagePredicates.idEquals(from.getHref().toASCIIString())); return builder.build(); + } protected String getName(String name) { diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java index 99d1780e52..3bab9811d2 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVAppTemplate.java @@ -20,14 +20,17 @@ package org.jclouds.vcloud.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; +import javax.annotation.Resource; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.compute.domain.CIMOperatingSystem; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.ImageBuilder; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; import org.jclouds.ovf.Envelope; -import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.domain.VAppTemplate; import com.google.common.base.Function; @@ -37,18 +40,26 @@ import com.google.common.base.Function; */ @Singleton public class ImageForVAppTemplate implements Function { - private final VCloudClient client; + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + public Logger logger = Logger.NULL; + + private final Function templateToEnvelope; private final FindLocationForResource findLocationForResource; @Inject - protected ImageForVAppTemplate(VCloudClient client, FindLocationForResource findLocationForResource) { - this.client = checkNotNull(client, "client"); + protected ImageForVAppTemplate(Function templateToEnvelope, + FindLocationForResource findLocationForResource) { + this.templateToEnvelope = checkNotNull(templateToEnvelope, "templateToEnvelope"); this.findLocationForResource = checkNotNull(findLocationForResource, "findLocationForResource"); } - @Override public Image apply(VAppTemplate from) { + checkNotNull(from, "VAppTemplate"); + Envelope ovf = templateToEnvelope.apply(from); + ImageBuilder builder = new ImageBuilder(); builder.ids(from.getHref().toASCIIString()); builder.uri(from.getHref()); @@ -59,7 +70,6 @@ public class ImageForVAppTemplate implements Function { // otherwise, it could be in a public catalog, which is not assigned to a VDC } builder.description(from.getDescription() != null ? from.getDescription() : from.getName()); - Envelope ovf = client.getVAppTemplateClient().getOvfEnvelopeForVAppTemplate(from.getHref()); builder.operatingSystem(CIMOperatingSystem.toComputeOs(ovf)); return builder.build(); } diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java index b7cebb5964..a72b84ac83 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException.java @@ -75,4 +75,5 @@ public class ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentExceptio } return ovf; } -} \ No newline at end of file +} + 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 e98b88dbc1..823bd76aed 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 @@ -18,8 +18,14 @@ */ package org.jclouds.vcloud.compute.strategy; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Predicates.not; +import static com.google.common.collect.Iterables.find; +import static com.google.common.collect.Iterables.get; +import static org.jclouds.Constants.PROPERTY_BUILD_VERSION; import static org.jclouds.compute.util.ComputeServiceUtils.getCores; import static org.jclouds.vcloud.compute.util.VCloudComputeUtils.getCredentialsFrom; +import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig; import java.net.URI; @@ -31,7 +37,11 @@ import javax.inject.Singleton; import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials; import org.jclouds.compute.domain.Template; import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.javax.annotation.Nullable; import org.jclouds.logging.Logger; +import org.jclouds.ovf.Network; +import org.jclouds.predicates.validators.DnsNameValidator; +import org.jclouds.vcloud.TaskStillRunningException; import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.compute.options.VCloudTemplateOptions; import org.jclouds.vcloud.domain.GuestCustomizationSection; @@ -39,14 +49,16 @@ import org.jclouds.vcloud.domain.NetworkConnection; import org.jclouds.vcloud.domain.NetworkConnectionSection; import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.VApp; +import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.domain.Vm; import org.jclouds.vcloud.domain.NetworkConnectionSection.Builder; import org.jclouds.vcloud.domain.network.IpAddressAllocationMode; +import org.jclouds.vcloud.domain.network.NetworkConfig; import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; -import com.google.common.base.Function; import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableSet; /** * @author Adrian Cole @@ -59,100 +71,218 @@ public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployA protected final VCloudClient client; protected final Predicate successTester; + protected final LoadingCache vAppTemplates; + protected final NetworkConfig defaultNetworkConfig; + protected final String buildVersion; @Inject - protected InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn(Predicate successTester, - VCloudClient client) { + protected InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn(VCloudClient client, + Predicate successTester, LoadingCache vAppTemplates, + NetworkConfig defaultNetworkConfig, @Named(PROPERTY_BUILD_VERSION) String buildVersion) { this.client = client; this.successTester = successTester; + this.vAppTemplates = vAppTemplates; + this.defaultNetworkConfig = defaultNetworkConfig; + this.buildVersion = buildVersion; } - public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName(String tag, String name, Template template) { - InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); + // TODO: filtering on "none" is a hack until we can filter on + // vAppTemplate.getNetworkConfigSection().getNetworkConfigs() where + // name = getChildren().NetworkConnectionSection.connection where ipallocationmode == none + Predicate networkWithNoIpAllocation = new Predicate() { + + @Override + public boolean apply(Network input) { + return "none".equals(input.getName()); + } + + }; + + /** + * per john ellis at bluelock, vCloud Director 1.5 is more strict than earlier versions. + *

+ * It appears to be 15 characters to match Windows' hostname limitation. Must be alphanumeric, at + * least one non-number character and hyphens and underscores are the only non-alpha character + * allowed. + */ + public static enum ComputerNameValidator { + INSTANCE; + + private DnsNameValidator validator; + + ComputerNameValidator(){ + this.validator = new DnsNameValidator(3, 15); + } + + public void validate(@Nullable String t) throws IllegalArgumentException { + this.validator.validate(t); + } + + } + + public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName(String group, String name, Template template) { + // no sense waiting until failures occur later + ComputerNameValidator.INSTANCE.validate(name); + + URI templateId = URI.create(template.getImage().getId()); + + VAppTemplate vAppTemplate = vAppTemplates.getUnchecked(templateId); + + if (vAppTemplate.getChildren().size() > 1) + throw new UnsupportedOperationException("we currently do not support multiple vms in a vAppTemplate " + + vAppTemplate); + + if (vAppTemplate.getNetworkSection().getNetworks().size() > 1) + throw new UnsupportedOperationException( + "we currently do not support multiple network connections in a vAppTemplate " + vAppTemplate); + + Network networkToConnect = get(vAppTemplate.getNetworkSection().getNetworks(), 0); + + NetworkConfig config; + // if we only have a disconnected network, let's add a new section for the upstream + // TODO: remove the disconnected entry + if (networkWithNoIpAllocation.apply(networkToConnect)) + config = defaultNetworkConfig; + else + config = defaultNetworkConfig.toBuilder().networkName(networkToConnect.getName()).build(); + + // note that in VCD 1.5, the network name after instantiation will be the same as the parent + InstantiateVAppTemplateOptions options = addNetworkConfig(config); // TODO make disk size specifiable // disk((long) ((template.getHardware().getVolumes().get(0).getSize()) * // 1024 * 1024l)); String customizationScript = VCloudTemplateOptions.class.cast(template.getOptions()).getCustomizationScript(); - IpAddressAllocationMode ipAddressAllocationMode = VCloudTemplateOptions.class.cast(template.getOptions()) + IpAddressAllocationMode ipAllocationMode = VCloudTemplateOptions.class.cast(template.getOptions()) .getIpAddressAllocationMode(); - options.description(VCloudTemplateOptions.class.cast(template.getOptions()).getDescription()); + String description = VCloudTemplateOptions.class.cast(template.getOptions()).getDescription(); + if (description == null) + description = vAppTemplate.getName(); + + options.description(description); options.deploy(false); options.powerOn(false); - if (!template.getOptions().shouldBlockUntilRunning()) - options.block(false); - URI VDC = URI.create(template.getLocation().getId()); - URI templateId = URI.create(template.getImage().getId()); logger.debug(">> instantiating vApp vDC(%s) template(%s) name(%s) options(%s) ", VDC, templateId, name, options); VApp vAppResponse = client.getVAppTemplateClient().createVAppInVDCByInstantiatingTemplate(name, VDC, templateId, options); - waitForTask(vAppResponse.getTasks().get(0), vAppResponse); + waitForTask(vAppResponse.getTasks().get(0)); logger.debug("<< instantiated VApp(%s)", vAppResponse.getName()); - // note customization is a serial concern at the moment - Vm vm = Iterables.get(client.getVAppClient().getVApp(vAppResponse.getHref()).getChildren(), 0); - if (customizationScript != null) { - logger.trace(">> updating customization vm(%s) ", vm.getName()); - waitForTask(updateVmWithCustomizationScript(vm, customizationScript), vAppResponse); - logger.trace("<< updated customization vm(%s) ", vm.getName()); - } - if (ipAddressAllocationMode != null) { - logger.trace(">> updating ipAddressAllocationMode(%s) vm(%s) ", ipAddressAllocationMode, vm.getName()); - waitForTask(updateVmWithIpAddressAllocationMode(vm, ipAddressAllocationMode), vAppResponse); - logger.trace("<< updated ipAddressAllocationMode vm(%s) ", vm.getName()); - } + // vm data is available after instantiate completes + vAppResponse = client.getVAppClient().getVApp(vAppResponse.getHref()); + + // per above check, we know there is only a single VM + Vm vm = get(vAppResponse.getChildren(), 0); + + // note we cannot do tasks in parallel or VCD will throw "is busy" errors + + // note we must do this before any other customizations as there is a dependency on + // valid naming conventions before you can perform commands such as updateCPUCount + logger.trace(">> updating customization vm(%s) name->(%s)", vm.getName(), name); + waitForTask(updateVmWithNameAndCustomizationScript(vm, name, customizationScript)); + logger.trace("<< updated customization vm(%s)", name); + + ensureVmHasAllocationModeOrPooled(vAppResponse, ipAllocationMode); + int cpuCount = new Double(getCores(template.getHardware())).intValue(); - logger.trace(">> updating cpuCount(%d) vm(%s) ", cpuCount, vm.getName()); - waitForTask(updateCPUCountOfVm(vm, cpuCount), vAppResponse); - logger.trace("<< updated cpuCount vm(%s) ", vm.getName()); + logger.trace(">> updating cpuCount(%d) vm(%s)", cpuCount, vm.getName()); + waitForTask(updateCPUCountOfVm(vm, cpuCount)); + logger.trace("<< updated cpuCount vm(%s)", vm.getName()); int memoryMB = template.getHardware().getRam(); - logger.trace(">> updating memoryMB(%d) vm(%s) ", memoryMB, vm.getName()); - waitForTask(updateMemoryMBOfVm(vm, memoryMB), vAppResponse); - logger.trace("<< updated memoryMB vm(%s) ", vm.getName()); - logger.trace(">> deploying and powering on vApp(%s) ", vAppResponse.getName()); - vAppResponse = blockOnDeployAndPowerOnIfConfigured(options, vAppResponse, client.getVAppClient() - .deployAndPowerOnVApp(vAppResponse.getHref())); + logger.trace(">> updating memoryMB(%d) vm(%s)", memoryMB, vm.getName()); + waitForTask(updateMemoryMBOfVm(vm, memoryMB)); + logger.trace("<< updated memoryMB vm(%s)", vm.getName()); + logger.trace(">> deploying vApp(%s)", vAppResponse.getName()); + waitForTask(client.getVAppClient().deployVApp(vAppResponse.getHref())); + logger.trace("<< deployed vApp(%s)", vAppResponse.getName()); + + // only after deploy is the password valid + vAppResponse = client.getVAppClient().getVApp(vAppResponse.getHref()); + + logger.trace(">> powering on vApp(%s)", vAppResponse.getName()); + client.getVAppClient().powerOnVApp(vAppResponse.getHref()); + return new NodeAndInitialCredentials(vAppResponse, vAppResponse.getHref().toASCIIString(), getCredentialsFrom(vAppResponse)); } - public void waitForTask(Task task, VApp vAppResponse) { + public void waitForTask(Task task) { if (!successTester.apply(task.getHref())) { - throw new RuntimeException(String.format("failed to %s %s: %s", task.getName(), vAppResponse.getName(), task)); + throw new TaskStillRunningException(task); } } - public Task updateVmWithCustomizationScript(Vm vm, String customizationScript) { + /** + * Naming constraints modifying a VM on a VApp in vCloud Director (at least v1.5) can be more + * strict than those in a vAppTemplate. For example, while it is possible to instantiate a + * vAppTemplate with a VM named (incorrectly) {@code Ubuntu_10.04}, you must change the name to a + * valid (alphanumeric underscore) name before you can update it. + */ + public Task updateVmWithNameAndCustomizationScript(Vm vm, String name, @Nullable String customizationScript) { 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); + guestConfiguration.setComputerName(name); + if (customizationScript != null) { + // In version 1.0.0, the api returns a script that loses newlines, so we cannot append to a + // customization script. + // TODO: parameterize whether to overwrite or append existing customization + if (!buildVersion.startsWith("1.0.0") && !"".endsWith(buildVersion) + && guestConfiguration.getCustomizationScript() != null) + customizationScript = guestConfiguration.getCustomizationScript() + "\n" + customizationScript; + + guestConfiguration.setCustomizationScript(customizationScript); + } return client.getVmClient().updateGuestCustomizationOfVm(guestConfiguration, vm.getHref()); } - public Task updateVmWithIpAddressAllocationMode(Vm vm, final IpAddressAllocationMode ipAddressAllocationMode) { + public void ensureVmHasAllocationModeOrPooled(VApp vApp, @Nullable IpAddressAllocationMode ipAllocationMode) { + Network networkToConnect = find(vApp.getNetworkSection().getNetworks(), not(networkWithNoIpAllocation)); + + Vm vm = get(vApp.getChildren(), 0); + NetworkConnectionSection net = vm.getNetworkConnectionSection(); - Builder builder = net.toBuilder(); - builder.connections(Iterables.transform(net.getConnections(), - new Function() { + checkArgument(net.getConnections().size() > 0, "no connections on vm %s", vm); - @Override - public NetworkConnection apply(NetworkConnection arg0) { - return arg0.toBuilder().connected(true).ipAddressAllocationMode(ipAddressAllocationMode).build(); - } + NetworkConnection toConnect = findWithPoolAllocationOrFirst(net); - })); - return client.getVmClient().updateNetworkConnectionOfVm(builder.build(), vm.getHref()); + if (ipAllocationMode == null) + ipAllocationMode = toConnect.getIpAddressAllocationMode(); + + // make sure that we are in fact allocating ips + if (ipAllocationMode == IpAddressAllocationMode.NONE) + ipAllocationMode = IpAddressAllocationMode.POOL; + + if (toConnect.isConnected() && toConnect.getIpAddressAllocationMode() == ipAllocationMode + && toConnect.getNetwork().equals(networkToConnect.getName())) { + // then we don't need to change the network settings, and can save a call + } else { + Builder builder = net.toBuilder(); + builder.connections(ImmutableSet.of(toConnect.toBuilder().network(networkToConnect.getName()).connected(true) + .ipAddressAllocationMode(ipAllocationMode).build())); + logger.trace(">> updating networkConnection vm(%s)", vm.getName()); + + waitForTask(client.getVmClient().updateNetworkConnectionOfVm(builder.build(), vm.getHref())); + logger.trace("<< updated networkConnection vm(%s)", vm.getName()); + + } + + } + + private NetworkConnection findWithPoolAllocationOrFirst(NetworkConnectionSection net) { + return find(net.getConnections(), new Predicate() { + + @Override + public boolean apply(NetworkConnection input) { + return input.getIpAddressAllocationMode() == IpAddressAllocationMode.POOL; + } + + }, get(net.getConnections(), 0)); } public Task updateCPUCountOfVm(Vm vm, int cpuCount) { @@ -162,12 +292,4 @@ public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployA public Task updateMemoryMBOfVm(Vm vm, int memoryInMB) { return client.getVmClient().updateMemoryMBOfVm(memoryInMB, vm.getHref()); } - - private VApp blockOnDeployAndPowerOnIfConfigured(InstantiateVAppTemplateOptions options, VApp vAppResponse, Task task) { - if (options.shouldBlock()) { - waitForTask(task, vAppResponse); - logger.debug("<< ready vApp(%s)", vAppResponse.getName()); - } - return client.getVAppClient().getVApp(vAppResponse.getHref()); - } } \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java index eb5bf45e9a..5fa129dc4c 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudComputeServiceAdapter.java @@ -35,6 +35,9 @@ import org.jclouds.compute.domain.Template; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.domain.Location; import org.jclouds.logging.Logger; +import org.jclouds.ovf.Envelope; +import org.jclouds.vcloud.TaskInErrorStateException; +import org.jclouds.vcloud.TaskStillRunningException; import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.VCloudMediaType; import org.jclouds.vcloud.compute.suppliers.OrgAndVDCToLocationSupplier; @@ -47,9 +50,11 @@ import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.suppliers.VAppTemplatesSupplier; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; import com.google.common.collect.ImmutableSet.Builder; /** @@ -69,18 +74,20 @@ public class VCloudComputeServiceAdapter implements ComputeServiceAdapter> nameToOrg; protected final Supplier> templates; + protected final Function templateToEnvelope; protected final Supplier> locations; @Inject protected VCloudComputeServiceAdapter(VCloudClient client, Predicate successTester, InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn booter, - Supplier> nameToOrg, VAppTemplatesSupplier templates, - OrgAndVDCToLocationSupplier locations) { + Supplier> nameToOrg, VAppTemplatesSupplier templates, + Function templateToEnvelope, OrgAndVDCToLocationSupplier locations) { this.client = checkNotNull(client, "client"); this.successTester = checkNotNull(successTester, "successTester"); this.booter = checkNotNull(booter, "booter"); this.nameToOrg = checkNotNull(nameToOrg, "nameToOrg"); this.templates = checkNotNull(templates, "templates"); + this.templateToEnvelope = checkNotNull(templateToEnvelope, "templateToEnvelope"); this.locations = checkNotNull(locations, "locations"); } @@ -114,7 +121,7 @@ public class VCloudComputeServiceAdapter implements ComputeServiceAdapter listImages() { - return templates.get(); + return supportedTemplates(); } @Override @@ -157,70 +164,79 @@ public class VCloudComputeServiceAdapter implements ComputeServiceAdapter> deleting vApp(%s)", vApp.getHref()); - waitForTask(client.getVAppClient().deleteVApp(vApp.getHref()), vApp); - logger.debug("<< deleted vApp(%s)", vApp.getHref()); - } - - VApp undeployVAppIfDeployed(VApp vApp) { + VApp vApp = cancelAnyRunningTasks(vappId); if (vApp.getStatus() != Status.OFF) { + logger.debug(">> powering off VApp vApp(%s), current status: %s", vApp.getName(), vApp.getStatus()); + try { + waitForTask(client.getVAppClient().powerOffVApp(vApp.getHref())); + vApp = client.getVAppClient().getVApp(vApp.getHref()); + logger.debug("<< %s vApp(%s)", vApp.getStatus(), vApp.getName()); + } catch (IllegalStateException e) { + logger.warn(e, "<< %s vApp(%s)", vApp.getStatus(), vApp.getName()); + } logger.debug(">> undeploying vApp(%s), current status: %s", vApp.getName(), vApp.getStatus()); try { - waitForTask(client.getVAppClient().undeployVApp(vApp.getHref()), vApp); + waitForTask(client.getVAppClient().undeployVApp(vApp.getHref())); vApp = client.getVAppClient().getVApp(vApp.getHref()); logger.debug("<< %s vApp(%s)", vApp.getStatus(), vApp.getName()); } catch (IllegalStateException e) { logger.warn(e, "<< %s vApp(%s)", vApp.getStatus(), vApp.getName()); } } - return vApp; + logger.debug(">> deleting vApp(%s)", vApp.getHref()); + waitForTask(client.getVAppClient().deleteVApp(vApp.getHref())); + logger.debug("<< deleted vApp(%s)", vApp.getHref()); + } + + VApp waitForPendingTasksToComplete(URI vappId) { + VApp vApp = client.getVAppClient().getVApp(vappId); + if (vApp.getTasks().size() == 0) + return vApp; + for (Task task : vApp.getTasks()) + waitForTask(task); + return client.getVAppClient().getVApp(vappId); + } + + VApp cancelAnyRunningTasks(URI vappId) { + VApp vApp = client.getVAppClient().getVApp(vappId); + if (vApp.getTasks().size() == 0) + return vApp; + for (Task task : vApp.getTasks()) { + try { + client.getTaskClient().cancelTask(task.getHref()); + waitForTask(task); + } catch (TaskInErrorStateException e) { + } + } + return client.getVAppClient().getVApp(vappId); + + } + + public void waitForTask(Task task) { + if (!successTester.apply(task.getHref())) + throw new TaskStillRunningException(task); } @Override public void rebootNode(String in) { URI id = URI.create(checkNotNull(in, "node.id")); - Task task = client.getVAppClient().resetVApp(id); - successTester.apply(task.getHref()); - + waitForTask(client.getVAppClient().resetVApp(id)); } @Override public void resumeNode(String in) { URI id = URI.create(checkNotNull(in, "node.id")); - Task task = client.getVAppClient().powerOnVApp(id); - successTester.apply(task.getHref()); + waitForTask(client.getVAppClient().powerOnVApp(id)); } @Override public void suspendNode(String in) { URI id = URI.create(checkNotNull(in, "node.id")); - Task task = client.getVAppClient().powerOffVApp(id); - successTester.apply(task.getHref()); + waitForTask(client.getVAppClient().powerOffVApp(id)); } } diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/util/VCloudComputeUtils.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/util/VCloudComputeUtils.java index 26d73bca86..93f197db70 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/util/VCloudComputeUtils.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/util/VCloudComputeUtils.java @@ -77,10 +77,6 @@ public class VCloudComputeUtils { public static LoginCredentials getCredentialsFrom(Vm vm) { LoginCredentials.Builder builder = LoginCredentials.builder(); - builder.user("root"); - if (vm.getOperatingSystemSection() != null && vm.getOperatingSystemSection().getDescription() != null - && vm.getOperatingSystemSection().getDescription().indexOf("Windows") >= 0) - builder.user("Administrator"); if (vm.getGuestCustomizationSection() != null) builder.password(vm.getGuestCustomizationSection().getAdminPassword()); return builder.build(); diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java index c54cee2235..e40ed27a47 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java @@ -20,20 +20,24 @@ package org.jclouds.vcloud.config; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Predicates.notNull; +import static com.google.common.base.Suppliers.compose; import static com.google.common.base.Throwables.propagate; import static com.google.common.collect.Iterables.concat; +import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.getLast; import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Maps.transformValues; import static com.google.common.collect.Maps.uniqueIndex; import static org.jclouds.Constants.PROPERTY_API_VERSION; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; +import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE; import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED; import java.net.URI; import java.util.Map; -import java.util.Map.Entry; import java.util.SortedMap; +import java.util.Map.Entry; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -50,6 +54,7 @@ import org.jclouds.http.RequiresHttp; import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.Redirection; import org.jclouds.http.annotation.ServerError; +import org.jclouds.ovf.Envelope; import org.jclouds.predicates.RetryablePredicate; import org.jclouds.rest.AsyncClientFactory; import org.jclouds.rest.AuthorizationException; @@ -61,6 +66,7 @@ import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.VCloudToken; import org.jclouds.vcloud.VCloudVersionsAsyncClient; import org.jclouds.vcloud.compute.functions.FindLocationForResource; +import org.jclouds.vcloud.compute.functions.ValidateVAppTemplateAndReturnEnvelopeOrThrowIllegalArgumentException; import org.jclouds.vcloud.domain.Catalog; import org.jclouds.vcloud.domain.CatalogItem; import org.jclouds.vcloud.domain.Org; @@ -68,6 +74,8 @@ import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.domain.VCloudSession; import org.jclouds.vcloud.domain.VDC; +import org.jclouds.vcloud.domain.network.FenceMode; +import org.jclouds.vcloud.endpoints.Network; import org.jclouds.vcloud.endpoints.OrgList; import org.jclouds.vcloud.features.CatalogAsyncClient; import org.jclouds.vcloud.features.CatalogClient; @@ -89,22 +97,25 @@ import org.jclouds.vcloud.functions.AllCatalogItemsInCatalog; import org.jclouds.vcloud.functions.AllCatalogItemsInOrg; import org.jclouds.vcloud.functions.AllCatalogsInOrg; import org.jclouds.vcloud.functions.AllVDCsInOrg; +import org.jclouds.vcloud.functions.DefaultNetworkNameInTemplate; import org.jclouds.vcloud.functions.OrgsForLocations; import org.jclouds.vcloud.functions.OrgsForNames; import org.jclouds.vcloud.functions.VAppTemplatesForCatalogItems; import org.jclouds.vcloud.handlers.ParseVCloudErrorFromHttpResponse; import org.jclouds.vcloud.internal.VCloudLoginAsyncClient; +import org.jclouds.vcloud.loaders.OVFLoader; +import org.jclouds.vcloud.loaders.VAppTemplateLoader; import org.jclouds.vcloud.predicates.TaskSuccess; import org.jclouds.vcloud.xml.ovf.VCloudResourceAllocationSettingDataHandler; import com.google.common.base.Function; import com.google.common.base.Predicate; -import static com.google.common.base.Predicates.*; import com.google.common.base.Supplier; -import static com.google.common.base.Suppliers.*; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; -import static com.google.common.collect.Iterables.*; import com.google.inject.Injector; import com.google.inject.Provides; import com.google.inject.TypeLiteral; @@ -192,6 +203,27 @@ public class VCloudRestClientModule extends RestClientModule>>() { }).to(new TypeLiteral() { }); + + bindCacheLoaders(); + + bind(new TypeLiteral>() { + }).annotatedWith(Network.class).to(new TypeLiteral() { + }); + + bind(new TypeLiteral>() { + }).to(new TypeLiteral() { + }); + + } + + protected void bindCacheLoaders() { + bind(new TypeLiteral>() { + }).to(new TypeLiteral() { + }); + + bind(new TypeLiteral>() { + }).to(new TypeLiteral() { + }); } @Provides @@ -486,7 +518,26 @@ public class VCloudRestClientModule extends RestClientModule>>>( authException, seconds, supplier); } + + + @Provides + @Singleton + protected FenceMode defaultFenceMode(@Named(PROPERTY_VCLOUD_DEFAULT_FENCEMODE) String fenceMode){ + return FenceMode.fromValue(fenceMode); + } + + @Provides + @Singleton + protected LoadingCache vAppTemplates(CacheLoader vAppTemplates) { + return CacheBuilder.newBuilder().build(vAppTemplates); + } + @Provides + @Singleton + protected LoadingCache envelopes(CacheLoader envelopes) { + return CacheBuilder.newBuilder().build(envelopes); + } + @Override protected void bindErrorHandlers() { bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseVCloudErrorFromHttpResponse.class); diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/VApp.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/VApp.java index 3efc1a5d86..2ba7ea4d79 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/VApp.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/VApp.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Set; import org.jclouds.javax.annotation.Nullable; +import org.jclouds.vcloud.domain.ovf.VCloudNetworkSection; /** * A VApp is the result of instantiation of a {@link VAppTemplate}.

note

@@ -77,4 +78,12 @@ public interface VApp extends ReferenceType { */ Set getChildren(); + /** + * description of the predefined vApp internal networks in this template + * + * @return null if the vApp is not yet instantiated + * @since vcloud api 1.0 + */ + @Nullable + VCloudNetworkSection getNetworkSection(); } \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/TaskImpl.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/TaskImpl.java index a38dd71f13..828bc29c61 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/TaskImpl.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/TaskImpl.java @@ -31,6 +31,8 @@ import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.TaskStatus; import org.jclouds.vcloud.domain.VCloudError; +import com.google.common.base.Objects; + /** * * @author Adrian Cole @@ -88,10 +90,9 @@ public class TaskImpl extends ReferenceTypeImpl implements Task { @Override public String toString() { - return "TaskImpl [endTime=" + endTime + ", error=" + error + ", expiryTime=" + expiryTime + ", operation=" - + operation + ", owner=" + owner + ", startTime=" + startTime + ", status=" + status + ", getHref()=" - + getHref() + ", getName()=" + getName() + ", getType()=" + getType() + ", toString()=" - + super.toString() + ", getClass()=" + getClass() + "]"; + return Objects.toStringHelper("").add("href", getHref()).add("name", getName()).add("owner", owner).add( + "operation", operation).add("startTime", startTime).add("endTime", endTime) + .add("expiryTime", expiryTime).add("error", error).toString(); } public Date getExpiryTime() { diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/VAppImpl.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/VAppImpl.java index f44a7639f6..fc7eb44f8e 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/VAppImpl.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/internal/VAppImpl.java @@ -31,6 +31,7 @@ import org.jclouds.vcloud.domain.Status; import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.VApp; import org.jclouds.vcloud.domain.Vm; +import org.jclouds.vcloud.domain.ovf.VCloudNetworkSection; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -51,9 +52,12 @@ public class VAppImpl extends ReferenceTypeImpl implements VApp { private final List tasks = Lists.newArrayList(); private final boolean ovfDescriptorUploaded; private final Set children = Sets.newLinkedHashSet(); - + @Nullable + private final VCloudNetworkSection networkSection; + public VAppImpl(String name, String type, URI id, Status status, ReferenceType vdc, @Nullable String description, - Iterable tasks, boolean ovfDescriptorUploaded, Iterable children) { + Iterable tasks, boolean ovfDescriptorUploaded, Iterable children, + @Nullable VCloudNetworkSection networkSection) { super(name, type, id); this.status = checkNotNull(status, "status"); this.vdc = vdc;// TODO: once <1.0 is killed check not null @@ -61,6 +65,7 @@ public class VAppImpl extends ReferenceTypeImpl implements VApp { Iterables.addAll(this.tasks, checkNotNull(tasks, "tasks")); this.ovfDescriptorUploaded = ovfDescriptorUploaded; Iterables.addAll(this.children, checkNotNull(children, "children")); + this.networkSection = networkSection; // can be null when copying } /** @@ -110,7 +115,15 @@ public class VAppImpl extends ReferenceTypeImpl implements VApp { public Set getChildren() { return children; } - + + /** + * {@inheritDoc} + */ + @Override + public VCloudNetworkSection getNetworkSection() { + return networkSection; + } + @Override public int hashCode() { final int prime = 31; diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/network/NetworkConfig.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/network/NetworkConfig.java index c2fb6708c6..3a5ec8b6af 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/network/NetworkConfig.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/domain/network/NetworkConfig.java @@ -23,12 +23,51 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.net.URI; import org.jclouds.javax.annotation.Nullable; +import org.jclouds.ovf.NetworkSection; /** * * @author Adrian Cole */ public class NetworkConfig { + + public Builder toBuilder() { + return builder().fromNetworkConfig(this); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String networkName; + private URI parentNetwork; + private FenceMode fenceMode; + + public Builder networkName(String networkName) { + this.networkName = networkName; + return this; + } + + public Builder parentNetwork(URI parentNetwork) { + this.parentNetwork = parentNetwork; + return this; + } + + public Builder fenceMode(FenceMode fenceMode) { + this.fenceMode = fenceMode; + return this; + } + + public Builder fromNetworkConfig(NetworkConfig in) { + return networkName(in.getNetworkName()).parentNetwork(in.getParentNetwork()).fenceMode(in.getFenceMode()); + } + + public NetworkConfig build() { + return new NetworkConfig(networkName, parentNetwork, fenceMode); + } + } + @Nullable private final String networkName; private final URI parentNetwork; @@ -87,7 +126,6 @@ public class NetworkConfig { return fenceMode; } - @Override public int hashCode() { final int prime = 31; diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java index 115182673c..fc48add5f6 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/AllCatalogItemsInOrg.java @@ -18,11 +18,9 @@ */ package org.jclouds.vcloud.functions; -import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Singleton; -import org.jclouds.logging.Logger; import org.jclouds.vcloud.domain.Catalog; import org.jclouds.vcloud.domain.CatalogItem; import org.jclouds.vcloud.domain.Org; @@ -36,9 +34,6 @@ import com.google.common.collect.Iterables; @Singleton public class AllCatalogItemsInOrg implements Function> { - @Resource - public Logger logger = Logger.NULL; - private final Function> allCatalogsInOrg; private final Function> allCatalogItemsInCatalog; diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/DefaultNetworkNameInTemplate.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/DefaultNetworkNameInTemplate.java new file mode 100644 index 0000000000..4c947e843d --- /dev/null +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/DefaultNetworkNameInTemplate.java @@ -0,0 +1,49 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you 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.functions; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.Iterables.get; + +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Singleton; + +import org.jclouds.logging.Logger; +import org.jclouds.ovf.Network; +import org.jclouds.vcloud.domain.VAppTemplate; + +import com.google.common.base.Function; + +@Singleton +public class DefaultNetworkNameInTemplate implements Function { + @Resource + protected Logger logger = Logger.NULL; + + @Override + public String apply(VAppTemplate vAppTemplate) { + checkArgument(vAppTemplate != null, "vAppTemplate was null!"); + Set networks = vAppTemplate.getNetworkSection().getNetworks(); + checkArgument(networks.size() > 0, "no networks found in vAppTemplate %s", vAppTemplate); + if (networks.size() > 1) + logger.warn("multiple networks found for %s, choosing first from: %s", vAppTemplate.getName(), networks); + return get(networks, 0).getName(); + } +} \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java index f2ea52af28..b4b733dc52 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/functions/VAppTemplatesInOrg.java @@ -18,20 +18,21 @@ */ package org.jclouds.vcloud.functions; -import java.util.Map; +import static com.google.common.base.Predicates.and; +import static com.google.common.base.Predicates.notNull; +import static com.google.common.collect.Iterables.filter; import javax.inject.Inject; import javax.inject.Singleton; -import org.jclouds.domain.Credentials; import org.jclouds.vcloud.domain.CatalogItem; import org.jclouds.vcloud.domain.Org; +import org.jclouds.vcloud.domain.Status; import org.jclouds.vcloud.domain.VAppTemplate; -import org.jclouds.vcloud.functions.AllCatalogItemsInOrg; import com.google.common.base.Function; -import com.google.common.base.Predicates; -import com.google.common.collect.Iterables; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableSet; /** * @author Adrian Cole @@ -39,13 +40,12 @@ import com.google.common.collect.Iterables; @Singleton public class VAppTemplatesInOrg implements Function> { - private final AllCatalogItemsInOrg allCatalogItemsInOrg; + private final Function> allCatalogItemsInOrg; private final Function, Iterable> vAppTemplatesForCatalogItems; @Inject - VAppTemplatesInOrg(AllCatalogItemsInOrg allCatalogItemsInOrg, - Function, Iterable> vAppTemplatesForCatalogItems, - Map credentialStore) { + VAppTemplatesInOrg(Function> allCatalogItemsInOrg, + Function, Iterable> vAppTemplatesForCatalogItems) { this.allCatalogItemsInOrg = allCatalogItemsInOrg; this.vAppTemplatesForCatalogItems = vAppTemplatesForCatalogItems; } @@ -54,7 +54,17 @@ public class VAppTemplatesInOrg implements Function> public Iterable apply(Org from) { Iterable catalogs = allCatalogItemsInOrg.apply(from); Iterable vAppTemplates = vAppTemplatesForCatalogItems.apply(catalogs); - return Iterables.filter(vAppTemplates, Predicates.notNull()); + return filter(vAppTemplates, and(notNull(), new Predicate(){ + + //TODO: test this + @Override + public boolean apply(VAppTemplate input) { + if (input == null) + return false; + return ImmutableSet.of(Status.RESOLVED, Status.OFF).contains(input.getStatus()); + } + + })); } } \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/OVFLoader.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/OVFLoader.java new file mode 100644 index 0000000000..719d35da80 --- /dev/null +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/OVFLoader.java @@ -0,0 +1,49 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you 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.loaders; + +import java.net.URI; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.logging.Logger; +import org.jclouds.ovf.Envelope; +import org.jclouds.vcloud.VCloudClient; + +import com.google.common.cache.CacheLoader; + +@Singleton +public class OVFLoader extends CacheLoader { + @Resource + protected Logger logger = Logger.NULL; + + private final VCloudClient client; + + @Inject + OVFLoader(VCloudClient client) { + this.client = client; + } + + @Override + public Envelope load(URI template) { + return client.getVAppTemplateClient().getOvfEnvelopeForVAppTemplate(template); + } +} \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/VAppTemplateLoader.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/VAppTemplateLoader.java new file mode 100644 index 0000000000..3189fafcd2 --- /dev/null +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/loaders/VAppTemplateLoader.java @@ -0,0 +1,49 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you 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.loaders; + +import java.net.URI; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.logging.Logger; +import org.jclouds.vcloud.VCloudClient; +import org.jclouds.vcloud.domain.VAppTemplate; + +import com.google.common.cache.CacheLoader; + +@Singleton +public class VAppTemplateLoader extends CacheLoader { + @Resource + protected Logger logger = Logger.NULL; + + private final VCloudClient client; + + @Inject + VAppTemplateLoader(VCloudClient client) { + this.client = client; + } + + @Override + public VAppTemplate load(URI template) { + return client.getVAppTemplateClient().getVAppTemplate(template); + } +} \ No newline at end of file diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java index 6212e5ddc7..de7f985fc2 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/options/InstantiateVAppTemplateOptions.java @@ -36,18 +36,13 @@ public class InstantiateVAppTemplateOptions { private Boolean customizeOnInstantiate; private String description = null; - private boolean block = true; private boolean deploy = true; private boolean powerOn = true; public String getDescription() { return description; } - - public boolean shouldBlock() { - return block; - } - + public boolean shouldDeploy() { return deploy; } @@ -80,14 +75,6 @@ public class InstantiateVAppTemplateOptions { this.powerOn = powerOn; return this; } - - /** - * block until instantiate or deployment operations complete? - */ - public InstantiateVAppTemplateOptions block(boolean block) { - this.block = block; - return this; - } /** * {@networkConfig VAppTemplate}s have internal networks that can be @@ -116,14 +103,6 @@ public class InstantiateVAppTemplateOptions { public static class Builder { - /** - * @see InstantiateVAppTemplateOptions#block - */ - public static InstantiateVAppTemplateOptions block(boolean block) { - InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); - return options.block(block); - } - /** * @see InstantiateVAppTemplateOptions#description */ @@ -161,14 +140,13 @@ public class InstantiateVAppTemplateOptions { @Override public String toString() { return "[networkConfig=" + networkConfig + ", customizeOnInstantiate=" + customizeOnInstantiate - + ", description=" + description + ", block=" + block + ", deploy=" + deploy + ", powerOn=" + powerOn + "]"; + + ", description=" + description + ", deploy=" + deploy + ", powerOn=" + powerOn + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + (block ? 1231 : 1237); result = prime * result + ((customizeOnInstantiate == null) ? 0 : customizeOnInstantiate.hashCode()); result = prime * result + (deploy ? 1231 : 1237); result = prime * result + ((description == null) ? 0 : description.hashCode()); @@ -186,8 +164,6 @@ public class InstantiateVAppTemplateOptions { if (getClass() != obj.getClass()) return false; InstantiateVAppTemplateOptions other = (InstantiateVAppTemplateOptions) obj; - if (block != other.block) - return false; if (customizeOnInstantiate == null) { if (other.customizeOnInstantiate != null) return false; diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/predicates/TaskSuccess.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/predicates/TaskSuccess.java index 04256295fd..00f3346a2b 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/predicates/TaskSuccess.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/predicates/TaskSuccess.java @@ -24,6 +24,7 @@ import javax.annotation.Resource; import javax.inject.Singleton; import org.jclouds.logging.Logger; +import org.jclouds.vcloud.TaskInErrorStateException; import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.TaskStatus; @@ -59,7 +60,7 @@ public class TaskSuccess implements Predicate { return false; logger.trace("%s: looking for status %s: currently: %s", task, TaskStatus.SUCCESS, task.getStatus()); if (task.getStatus() == TaskStatus.ERROR) - throw new RuntimeException("error on task: " + task.getHref() + " error: " + task.getError()); + throw new TaskInErrorStateException(task); return task.getStatus() == TaskStatus.SUCCESS; } diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppHandler.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppHandler.java index 5cfeb16997..a39e2d4c44 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppHandler.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppHandler.java @@ -35,6 +35,8 @@ import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.VApp; import org.jclouds.vcloud.domain.Vm; import org.jclouds.vcloud.domain.internal.VAppImpl; +import org.jclouds.vcloud.domain.ovf.VCloudNetworkSection; +import org.jclouds.vcloud.xml.ovf.VCloudNetworkSectionHandler; import org.xml.sax.Attributes; import org.xml.sax.SAXException; @@ -48,11 +50,14 @@ public class VAppHandler extends ParseSax.HandlerWithResult { protected final TaskHandler taskHandler; protected final VmHandler vmHandler; + protected final VCloudNetworkSectionHandler networkSectionHandler; @Inject - public VAppHandler(TaskHandler taskHandler, VmHandler vmHandler) { + public VAppHandler(TaskHandler taskHandler, VmHandler vmHandler, + VCloudNetworkSectionHandler networkSectionHandler) { this.taskHandler = taskHandler; this.vmHandler = vmHandler; + this.networkSectionHandler = networkSectionHandler; } protected StringBuilder currentText = new StringBuilder(); @@ -66,11 +71,13 @@ public class VAppHandler extends ParseSax.HandlerWithResult { private boolean inChildren; private boolean inTasks; + private boolean inNetworkSection; protected Set children = Sets.newLinkedHashSet(); + private VCloudNetworkSection networkSection; public VApp getResult() { return new VAppImpl(template.getName(), template.getType(), template.getHref(), status, vdc, description, tasks, - ovfDescriptorUploaded, children); + ovfDescriptorUploaded, children, networkSection); } protected int depth = 0; @@ -84,12 +91,16 @@ public class VAppHandler extends ParseSax.HandlerWithResult { inChildren = true; } else if (equalsOrSuffix(qName, "Tasks")) { inTasks = true; + } else if (equalsOrSuffix(qName, "NetworkSection")) { + inNetworkSection = true; } } if (inChildren) { vmHandler.startElement(uri, localName, qName, attrs); } else if (inTasks) { taskHandler.startElement(uri, localName, qName, attrs); + } else if (inNetworkSection) { + networkSectionHandler.startElement(uri, localName, qName, attrs); } else if (equalsOrSuffix(qName, "VApp")) { template = newReferenceType(attributes); if (attributes.containsKey("status")) @@ -111,12 +122,17 @@ public class VAppHandler extends ParseSax.HandlerWithResult { this.tasks.add(taskHandler.getResult()); } else if (equalsOrSuffix(qName, "Description")) { description = SaxUtils.currentOrNull(currentText); + } else if (equalsOrSuffix(qName, "NetworkSection")) { + inNetworkSection = false; + this.networkSection = networkSectionHandler.getResult(); } } if (inChildren) { vmHandler.endElement(uri, name, qName); } else if (inTasks) { taskHandler.endElement(uri, name, qName); + } else if (inNetworkSection) { + networkSectionHandler.endElement(uri, name, qName); } else if (equalsOrSuffix(qName, "ovfDescriptorUploaded")) { ovfDescriptorUploaded = Boolean.parseBoolean(SaxUtils.currentOrNull(currentText)); } @@ -124,11 +140,14 @@ public class VAppHandler extends ParseSax.HandlerWithResult { } public void characters(char ch[], int start, int length) { - currentText.append(ch, start, length); if (inTasks) taskHandler.characters(ch, start, length); - if (inChildren) + else if (inChildren) vmHandler.characters(ch, start, length); + else if (inNetworkSection) + networkSectionHandler.characters(ch, start, length); + else + currentText.append(ch, start, length); } } diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppTemplateHandler.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppTemplateHandler.java index 8a49e1447b..43d66a814b 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppTemplateHandler.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/xml/VAppTemplateHandler.java @@ -18,6 +18,7 @@ */ package org.jclouds.vcloud.xml; +import static org.jclouds.util.SaxUtils.equalsOrSuffix; import static org.jclouds.vcloud.util.Utils.newReferenceType; import java.util.List; @@ -83,11 +84,11 @@ public class VAppTemplateHandler extends ParseSax.HandlerWithResult attributes = SaxUtils.cleanseAttributes(attrs); - if (qName.endsWith("Children")) { + if (equalsOrSuffix(qName, "Children")) { inChildren = true; - } else if (qName.endsWith("Tasks")) { + } else if (equalsOrSuffix(qName, "Tasks")) { inTasks = true; - } else if (qName.endsWith("NetworkSection")) { + } else if (equalsOrSuffix(qName, "NetworkSection")) { inNetworkSection = true; } if (inChildren) { @@ -96,26 +97,26 @@ public class VAppTemplateHandler extends ParseSax.HandlerWithResult attributes = SaxUtils.cleanseAttributes(attrs); - if (qName.endsWith("NetworkSection")) { + if (equalsOrSuffix(qName, "NetworkSection")) { this.net = Utils.newReferenceType(attributes); } networkSectionHandler.startElement(uri, localName, qName, attrs); diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java index 0aa1667708..d77d684bd3 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/binders/BindInstantiateVAppTemplateParamsToXmlPayloadTest.java @@ -24,31 +24,35 @@ import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig; +import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE; import java.io.IOException; import java.net.URI; import java.util.Map; import java.util.Properties; +import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.util.Strings2; -import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.VCloudPropertiesBuilder; import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.domain.internal.ReferenceTypeImpl; import org.jclouds.vcloud.domain.network.FenceMode; import org.jclouds.vcloud.domain.network.NetworkConfig; -import org.jclouds.vcloud.domain.ovf.VCloudNetworkSection; import org.jclouds.vcloud.endpoints.Network; -import org.jclouds.vcloud.features.VAppTemplateClient; import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; import org.testng.annotations.Test; +import com.google.common.base.Function; +import com.google.common.base.Functions; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.inject.AbstractModule; import com.google.inject.Guice; @@ -63,22 +67,37 @@ import com.google.inject.name.Names; */ @Test(groups = "unit") public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { - Injector createInjector(URI vAppTemplate, VAppTemplate value) { - final VCloudClient client = createMock(VCloudClient.class); - final VAppTemplateClient tclient = createMock(VAppTemplateClient.class); - - expect(client.getVAppTemplateClient()).andReturn(tclient).anyTimes(); - expect(tclient.getVAppTemplate(vAppTemplate)).andReturn(value).anyTimes(); - replay(client); - replay(tclient); + Injector createInjector(final URI vAppTemplate, final VAppTemplate value) { return Guice.createInjector(new AbstractModule() { + @SuppressWarnings("unused") + @Provides + @Singleton + @Network + protected Function templateToDefaultNetworkName() { + return Functions.forMap(ImmutableMap.of(value, "vAppNet-vApp Internal")); + } + + @SuppressWarnings("unused") + @Provides + @Singleton + protected LoadingCache templateIdToVAppTemplate() { + return CacheBuilder.newBuilder().build( + CacheLoader.from(Functions.forMap(ImmutableMap.of(vAppTemplate, value)))); + } + @Override protected void configure() { Properties props = new Properties(); Names.bindProperties(binder(), checkNotNull(new VCloudPropertiesBuilder(props).build(), "properties")); - bind(VCloudClient.class).toInstance(client); + } + + @SuppressWarnings("unused") + @Provides + @Singleton + public FenceMode defaultFenceMode(@Named(PROPERTY_VCLOUD_DEFAULT_FENCEMODE) String fenceMode) { + return FenceMode.fromValue(fenceMode); } @SuppressWarnings("unused") @@ -86,7 +105,8 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { @Provides @Singleton ReferenceType provideNetwork() { - return new ReferenceTypeImpl(null, null, URI.create("https://vcenterprise.bluelock.com/api/v1.0/network/1990")); + return new ReferenceTypeImpl(null, null, URI + .create("https://vcenterprise.bluelock.com/api/v1.0/network/1990")); } }); } @@ -94,91 +114,72 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { public void testDefault() 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); String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams.xml")); GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes(); expect(request.getArgs()).andReturn(ImmutableList. of(new InstantiateVAppTemplateOptions())) - .atLeastOnce(); + .atLeastOnce(); request.setPayload(expected); - expect(template.getNetworkSection()).andReturn(net).atLeastOnce(); - expect(net.getNetworks()).andReturn( - ImmutableSet. of(new org.jclouds.ovf.Network("vAppNet-vApp Internal", null))); - - replay(request); - replay(template); - replay(net); + replay(request, template); BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( - BindInstantiateVAppTemplateParamsToXmlPayload.class); + BindInstantiateVAppTemplateParamsToXmlPayload.class); Map map = Maps.newHashMap(); map.put("name", "my-vapp"); map.put("template", templateUri.toASCIIString()); binder.bindToRequest(request, map); - verify(request); - verify(template); - verify(net); - + verify(request, template); } public void testDescription() 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); - String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams-description.xml")); + String expected = Strings2.toStringAndClose(getClass() + .getResourceAsStream("/instantiationparams-description.xml")); GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes(); expect(request.getArgs()).andReturn( - ImmutableList. of(new InstantiateVAppTemplateOptions().description("my foo"))).atLeastOnce(); + ImmutableList. of(new InstantiateVAppTemplateOptions().description("my foo"))).atLeastOnce(); request.setPayload(expected); - expect(template.getNetworkSection()).andReturn(net).atLeastOnce(); - expect(net.getNetworks()).andReturn( - ImmutableSet. of(new org.jclouds.ovf.Network("vAppNet-vApp Internal", null))); - - replay(request); - replay(template); - replay(net); + replay(request, template); BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( - BindInstantiateVAppTemplateParamsToXmlPayload.class); + BindInstantiateVAppTemplateParamsToXmlPayload.class); Map map = Maps.newHashMap(); map.put("name", "my-vapp"); map.put("template", templateUri.toASCIIString()); binder.bindToRequest(request, map); - verify(request); - verify(template); - verify(net); + verify(request, template); } - @Test(expectedExceptions = IllegalArgumentException.class) public void testWhenTemplateDoesntExist() throws IOException { URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); - VAppTemplate template = null; + VAppTemplate template = createMock(VAppTemplate.class); String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams.xml")); GeneratedHttpRequest request = createMock(GeneratedHttpRequest.class); expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes(); expect(request.getArgs()).andReturn(ImmutableList. of()).atLeastOnce(); request.setPayload(expected); - replay(request); + replay(request, template); BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( - BindInstantiateVAppTemplateParamsToXmlPayload.class); + BindInstantiateVAppTemplateParamsToXmlPayload.class); Map map = Maps.newHashMap(); map.put("name", "my-vapp"); map.put("template", templateUri.toASCIIString()); binder.bindToRequest(request, map); - verify(request); + verify(request, template); } @@ -198,7 +199,7 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { replay(request); BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( - BindInstantiateVAppTemplateParamsToXmlPayload.class); + BindInstantiateVAppTemplateParamsToXmlPayload.class); Map map = Maps.newHashMap(); map.put("name", "my-vapp"); @@ -211,10 +212,10 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { public void testWithNetworkNameFenceMode() throws IOException { URI templateUri = URI.create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/3"); - VAppTemplate template = null; + VAppTemplate template = createMock(VAppTemplate.class); - InstantiateVAppTemplateOptions options = addNetworkConfig(new NetworkConfig("aloha", - URI.create("https://vcenterprise.bluelock.com/api/v1.0/network/1991"), FenceMode.NAT_ROUTED)); + InstantiateVAppTemplateOptions options = addNetworkConfig(new NetworkConfig("aloha", URI + .create("https://vcenterprise.bluelock.com/api/v1.0/network/1991"), FenceMode.NAT_ROUTED)); String expected = Strings2.toStringAndClose(getClass().getResourceAsStream("/instantiationparams-network.xml")); @@ -222,16 +223,16 @@ public class BindInstantiateVAppTemplateParamsToXmlPayloadTest { expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes(); expect(request.getArgs()).andReturn(ImmutableList. of(options)).atLeastOnce(); request.setPayload(expected); - replay(request); + replay(request, template); BindInstantiateVAppTemplateParamsToXmlPayload binder = createInjector(templateUri, template).getInstance( - BindInstantiateVAppTemplateParamsToXmlPayload.class); + BindInstantiateVAppTemplateParamsToXmlPayload.class); Map 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(request, template); } } diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java index 2d5ec8acfb..aa6185c6c5 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/VCloudComputeServiceLiveTest.java @@ -18,22 +18,12 @@ */ package org.jclouds.vcloud.compute; -import static org.testng.Assert.assertEquals; - import org.jclouds.compute.BaseComputeServiceLiveTest; -import org.jclouds.compute.ComputeServiceContextFactory; -import org.jclouds.compute.domain.ComputeMetadata; -import org.jclouds.compute.domain.ComputeType; import org.jclouds.compute.domain.NodeMetadata; -import org.jclouds.rest.RestContext; import org.jclouds.sshj.config.SshjSshClientModule; -import org.jclouds.vcloud.VCloudAsyncClient; -import org.jclouds.vcloud.VCloudClient; -import org.jclouds.vcloud.domain.VApp; import org.testng.annotations.Test; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import com.google.inject.Module; /** @@ -46,47 +36,30 @@ public class VCloudComputeServiceLiveTest extends BaseComputeServiceLiveTest { public VCloudComputeServiceLiveTest() { provider = "vcloud"; - // vcloud requires instantiate before deploy, which takes longer than 30 seconds - nonBlockDurationSeconds = 300; + } + + @Override + public void setServiceDefaults() { + // extremely short names needed so that we don't get errors relating to + // guestCustomization.computerName being too long + group = "vcd"; + } + + @Override + public void testOptionToNotBlock() { + // start call has to block until deploy } @Override protected Module getSshModule() { return new SshjSshClientModule(); } - + // vcloud does not support metadata @Override protected void checkUserMetadataInNodeEquals(NodeMetadata node, ImmutableMap userMetadata) { assert node.getUserMetadata().equals(ImmutableMap. of()) : String.format( - "node userMetadata did not match %s %s", userMetadata, node); - } - - @Override - public void testListNodes() throws Exception { - for (ComputeMetadata node : client.listNodes()) { - assert node.getProviderId() != null; - assert node.getLocation() != null; - assertEquals(node.getType(), ComputeType.NODE); - NodeMetadata allData = client.getNodeMetadata(node.getId()); - System.out.println(allData.getHardware()); - RestContext tmContext = new ComputeServiceContextFactory( - setupRestProperties()).createContext(provider, identity, credential, ImmutableSet. of(), - setupProperties()).getProviderSpecificContext(); - VApp vApp = tmContext.getApi().getVAppClient().findVAppInOrgVDCNamed(null, null, allData.getName()); - assertEquals(vApp.getName(), allData.getName()); - } + "node userMetadata did not match %s %s", userMetadata, node); } - @Test(enabled = true, dependsOnMethods = "testSuspendResume") - @Override - public void testGetNodesWithDetails() throws Exception { - super.testGetNodesWithDetails(); - } - - @Test(enabled = true, dependsOnMethods = { "testListNodes", "testGetNodesWithDetails" }) - @Override - public void testDestroyNodes() { - super.testDestroyNodes(); - } } \ No newline at end of file diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest.java new file mode 100644 index 0000000000..7cd597f4a6 --- /dev/null +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/compute/strategy/InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest.java @@ -0,0 +1,72 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you 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.strategy; + +import static org.testng.Assert.assertEquals; + +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.vcloud.compute.BaseVCloudComputeServiceExpectTest; +import org.jclouds.vcloud.domain.VApp; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; + +/** + * + * @author Adrian Cole + */ +@Test(singleThreaded = true, testName = "InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest") +public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOnExpectTest extends + BaseVCloudComputeServiceExpectTest { + + // TODO: finish me + @Test(enabled = false) + public void testCreateNodeUsingVCloud1_0ApiAgainstVCloudDirector1_5WhenVAppTemplateHasNetworkNamedNone() + throws Exception { + ComputeService compute = requestsSendResponses(ImmutableMap. builder().put( + versionsRequest, versionsResponseFromVCD1_5).put(version1_0LoginRequest, + successfulVersion1_0LoginResponseFromVCD1_5WithSingleOrg).put(version1_0GetOrgRequest, + successfulVersion1_0GetOrgResponseFromVCD1_5WithSingleTasksListVDCAndNetwork).put( + version1_0GetCatalogRequest, successfulVersion1_0GetCatalogResponseFromVCD1_5WithSingleTemplate).put( + version1_0GetCatalogItemRequest, successfulVersion1_0GetCatalogItemResponseFromVCD1_5ForTemplate).put( + version1_0GetVDCRequest, successfulVersion1_0GetVDCResponseFromVCD1_5WithSingleTemplateAndNetwork).put( + version1_0GetVAppTemplateRequest, + successfulVersion1_0GetVAppTemplateResponseFromVCD1_5WithSingleVMAndVDCParent).put( + version1_0GetOVFForVAppTemplateRequest, + successfulVersion1_0GetOVFForVAppTemplateResponseFromVCD1_5WithSingleVM).build()); + + InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn starter = compute.getContext() + .utils().injector().getInstance( + InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn.class); + + String group = "group"; + String name = "group-abcd"; + + NodeAndInitialCredentials appAndCreds = starter.createNodeWithGroupEncodedIntoName(group, name, compute + .templateBuilder().build()); + + assertEquals(appAndCreds.getNode().getName(), name); + assertEquals(appAndCreds.getCredentials(), LoginCredentials.builder().user("root").password("fromVApp").build()); + + } +} diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/features/CatalogClientLiveTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/features/CatalogClientLiveTest.java index 5fc3edda7e..b9ea2a4eb8 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/features/CatalogClientLiveTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/features/CatalogClientLiveTest.java @@ -43,6 +43,7 @@ public class CatalogClientLiveTest extends BaseVCloudClientLiveTest { @Test public void testFindCatalogIsWriteable() throws Exception { - assertEquals(getVCloudApi().getCatalogClient().findCatalogInOrgNamed(null, null).isReadOnly(), false); + // default catalog should be the public one, unless we are in vCloud 1.0.0 where public catalogs don't work + assertEquals(getVCloudApi().getCatalogClient().findCatalogInOrgNamed(null, null).isReadOnly(), buildVersion.startsWith("1.5")); } } \ No newline at end of file diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/features/VmClientLiveTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/features/VmClientLiveTest.java index d1014fe7ae..eee3b7ecb8 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/features/VmClientLiveTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/features/VmClientLiveTest.java @@ -98,7 +98,7 @@ public class VmClientLiveTest extends BaseVCloudClientLiveTest { public void testExtendedOptionsWithCustomizationScript() throws Exception { String PARSE_VMTOOLSD = "vmtoolsd --cmd=\"info-get guestinfo.ovfenv\" |grep vCloud_CustomizationInfo|sed 's/.*value=\"\\(.*\\)\".*/\\1/g'"; - String group = prefix + "customize"; + String group = prefix + "cus"; NodeMetadata node = null; try { diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java index db0ce26cc8..84f2ad01c0 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudAsyncClientTest.java @@ -32,6 +32,8 @@ import javax.inject.Singleton; import org.jclouds.http.HttpRequest; import org.jclouds.http.RequiresHttp; +import org.jclouds.ovf.Envelope; +import org.jclouds.ovf.xml.EnvelopeHandlerTest; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.RestClientTest; @@ -44,6 +46,7 @@ import org.jclouds.vcloud.domain.AllocationModel; import org.jclouds.vcloud.domain.Org; import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.Task; +import org.jclouds.vcloud.domain.VAppTemplate; import org.jclouds.vcloud.domain.VCloudSession; import org.jclouds.vcloud.domain.VDC; import org.jclouds.vcloud.domain.VDCStatus; @@ -53,15 +56,19 @@ import org.jclouds.vcloud.domain.internal.OrgImpl; import org.jclouds.vcloud.domain.internal.ReferenceTypeImpl; import org.jclouds.vcloud.domain.internal.VDCImpl; import org.jclouds.vcloud.filters.SetVCloudTokenCookie; +import org.jclouds.vcloud.xml.VAppTemplateHandlerTest; import org.testng.annotations.Test; +import com.google.common.base.Functions; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; +import com.google.common.cache.CacheLoader; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.inject.AbstractModule; import com.google.inject.Module; +import com.google.inject.TypeLiteral; /** * Tests behavior of {@code VCloudAsyncClient} @@ -182,6 +189,16 @@ public abstract class BaseVCloudAsyncClientTest extends RestClientTest { bind(OrgCatalogSupplier.class).to(TestOrgCatalogSupplier.class); bind(OrgCatalogItemSupplier.class).to(TestOrgCatalogItemSupplier.class); } + + @SuppressWarnings("unchecked") + @Override + protected void bindCacheLoaders() { + bind(new TypeLiteral>() { + }).toInstance((CacheLoader) CacheLoader.from(Functions.constant(VAppTemplateHandlerTest.parseTemplate()))); + + bind(new TypeLiteral>() { + }).toInstance((CacheLoader) CacheLoader.from(Functions.constant(EnvelopeHandlerTest.parseEnvelope()))); + } @Override protected Supplier>> provideOrgVDCSupplierCache( diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudClientLiveTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudClientLiveTest.java index 4ba2dbe5cd..8b3b86b884 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudClientLiveTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/internal/BaseVCloudClientLiveTest.java @@ -42,7 +42,8 @@ import com.google.inject.Module; */ @Test(groups = "live", enabled = true, singleThreaded = true) public abstract class BaseVCloudClientLiveTest extends BaseVersionedServiceLiveTest { - protected String prefix = System.getProperty("user.name"); + // username is too long for name constraints + protected String prefix = "vcd"; protected ComputeService client; diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppHandlerTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppHandlerTest.java index 30292b73a7..d953600aec 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppHandlerTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppHandlerTest.java @@ -71,6 +71,7 @@ public class VAppHandlerTest { .create("https://vcenterprise.bluelock.com/api/v1.0/vdc/1014839439"))); assertEquals(result.getTasks(), ImmutableList.of()); assert result.isOvfDescriptorUploaded(); + assert result.getNetworkSection() != null; Vm vm = Iterables.getOnlyElement(result.getChildren()); VmHandlerTest.checkVm(vm); } diff --git a/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppTemplateHandlerTest.java b/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppTemplateHandlerTest.java index 024ea9ee4b..9bfe3b80e5 100644 --- a/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppTemplateHandlerTest.java +++ b/apis/vcloud/src/test/java/org/jclouds/vcloud/xml/VAppTemplateHandlerTest.java @@ -54,10 +54,7 @@ import com.google.inject.Injector; public class VAppTemplateHandlerTest { public void testUbuntuTemplate() { - InputStream is = getClass().getResourceAsStream("/vAppTemplate.xml"); - Injector injector = Guice.createInjector(new SaxParserModule()); - Factory factory = injector.getInstance(ParseSax.Factory.class); - VAppTemplate result = factory.create(injector.getInstance(VAppTemplateHandler.class)).parse(is); + VAppTemplate result = parseTemplate(); assertEquals(result.getName(), "Ubuntu Template"); assertEquals(result.getHref(), URI .create("https://vcenterprise.bluelock.com/api/v1.0/vAppTemplate/vappTemplate-1201908921")); @@ -118,6 +115,14 @@ public class VAppTemplateHandlerTest { } + public static VAppTemplate parseTemplate() { + InputStream is = VAppTemplateHandlerTest.class.getResourceAsStream("/vAppTemplate.xml"); + Injector injector = Guice.createInjector(new SaxParserModule()); + Factory factory = injector.getInstance(ParseSax.Factory.class); + VAppTemplate result = factory.create(injector.getInstance(VAppTemplateHandler.class)).parse(is); + return result; + } + public void testCopyingTemplate() { InputStream is = getClass().getResourceAsStream("/vAppTemplate-copying.xml"); Injector injector = Guice.createInjector(new SaxParserModule()); @@ -148,4 +153,14 @@ public class VAppTemplateHandlerTest { assertEquals(result.getNetworkSection(), null); } + + public void testVAppTemplateWithNewlinesAndNamespacedElements() { + InputStream is = getClass().getResourceAsStream("/vAppTemplate1.0-vcd15_withNewlines.xml"); + Injector injector = Guice.createInjector(new SaxParserModule()); + Factory factory = injector.getInstance(ParseSax.Factory.class); + + factory.create(injector.getInstance(VAppTemplateHandler.class)).parse(is); + } + + } diff --git a/apis/vcloud/src/test/resources/vAppTemplate1.0-vcd15_withNewlines.xml b/apis/vcloud/src/test/resources/vAppTemplate1.0-vcd15_withNewlines.xml new file mode 100644 index 0000000000..9f41d81442 --- /dev/null +++ b/apis/vcloud/src/test/resources/vAppTemplate1.0-vcd15_withNewlines.xml @@ -0,0 +1,109 @@ + + + + + + + + Windows 2008 R2 Standard Edition +Service Pack 1 +Internet Explorer 9 + + + + Windows 2008 R2 Standard Edition +Service Pack 1 +Internet Explorer 9 + + Specifies the available VM network connections + 0 + + 0 + 212.54.128.56 + true + 00:50:56:01:0d:3c + POOL + + + + Specifies Guest OS Customization Settings + true + true + false + false + true + true + $6fEPL93 + false + Win2008r2Stand + + ac2ce03d-0491-46f7-afc6-37ffe5b30f74 + + + + The list of logical networks + + + + + + The configuration parameters for logical networks + + + + + true + 212.54.128.1 + 255.255.255.0 + 109.233.48.141 + 109.233.48.142 + + + 212.54.128.4 + 212.54.128.220 + + + + bridged + + + false + 3600 + 7200 + + 212.54.128.201 + 212.54.128.254 + + + + true + + + true + ipTranslation + allowTraffic + + + automatic + ac2ce03d-0491-46f7-afc6-37ffe5b30f74 + 0 + + + + + + false + + + + Lease settings section + + 0 + + + VApp template customization section + true + + \ No newline at end of file