All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jclouds.vcloud.compute.strategy.InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn Maven / Gradle / Ivy

There is a newer version: 1.8.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF 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 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.compute.util.ComputeServiceUtils.getCores;
import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue;
import static org.jclouds.vcloud.compute.util.VCloudComputeUtils.getCredentialsFrom;
import static org.jclouds.vcloud.options.InstantiateVAppTemplateOptions.Builder.addNetworkConfig;

import java.net.URI;
import java.util.Map;

import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
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.rest.annotations.BuildVersion;
import org.jclouds.vcloud.TaskStillRunningException;
import org.jclouds.vcloud.VCloudApi;
import org.jclouds.vcloud.compute.options.VCloudTemplateOptions;
import org.jclouds.vcloud.domain.GuestCustomizationSection;
import org.jclouds.vcloud.domain.NetworkConnection;
import org.jclouds.vcloud.domain.NetworkConnectionSection;
import org.jclouds.vcloud.domain.NetworkConnectionSection.Builder;
import org.jclouds.vcloud.domain.Task;
import org.jclouds.vcloud.domain.VApp;
import org.jclouds.vcloud.domain.VAppTemplate;
import org.jclouds.vcloud.domain.Vm;
import org.jclouds.vcloud.domain.network.IpAddressAllocationMode;
import org.jclouds.vcloud.domain.network.NetworkConfig;
import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;

@Singleton
public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn {
   @Resource
   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
   protected Logger logger = Logger.NULL;

   protected final VCloudApi client;
   protected final Predicate successTester;
   protected final LoadingCache vAppTemplates;
   protected final NetworkConfigurationForNetworkAndOptions networkConfigurationForNetworkAndOptions;
   protected final String buildVersion;


   @Inject
   protected InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployAndPowerOn(VCloudApi client,
            Predicate successTester, LoadingCache vAppTemplates, NetworkConfigurationForNetworkAndOptions networkConfigurationForNetworkAndOptions,
            @BuildVersion String buildVersion) {
      this.client = client;
      this.successTester = successTester;
      this.vAppTemplates = vAppTemplates;
      this.networkConfigurationForNetworkAndOptions = networkConfigurationForNetworkAndOptions;
      this.buildVersion = buildVersion;
   }
   
   /**
    * 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); VApp vAppResponse = instantiateVAppFromTemplate(name, template); waitForTask(vAppResponse.getTasks().get(0)); logger.debug("<< instantiated VApp(%s)", vAppResponse.getName()); // vm data is available after instantiate completes vAppResponse = client.getVAppApi().getVApp(vAppResponse.getHref()); // per above check, we know there is only a single VM Vm vm = get(vAppResponse.getChildren(), 0); template.getOptions().userMetadata(ComputeServiceConstants.NODE_GROUP_KEY, group); VCloudTemplateOptions vOptions = VCloudTemplateOptions.class.cast(template.getOptions()); // 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, vOptions.getCustomizationScript())); logger.trace("<< updated customization vm(%s)", name); ensureVmHasAllocationModeOrPooled(vAppResponse, vOptions.getIpAddressAllocationMode()); int cpuCount = (int) getCores(template.getHardware()); 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)); logger.trace("<< updated memoryMB vm(%s)", vm.getName()); logger.trace(">> deploying vApp(%s)", vAppResponse.getName()); waitForTask(client.getVAppApi().deployVApp(vAppResponse.getHref())); logger.trace("<< deployed vApp(%s)", vAppResponse.getName()); // only after deploy is the password valid vAppResponse = client.getVAppApi().getVApp(vAppResponse.getHref()); logger.trace(">> powering on vApp(%s)", vAppResponse.getName()); client.getVAppApi().powerOnVApp(vAppResponse.getHref()); return new NodeAndInitialCredentials(vAppResponse, vAppResponse.getHref().toASCIIString(), getCredentialsFrom(vAppResponse)); } @VisibleForTesting protected VApp instantiateVAppFromTemplate(String name, Template template) { VCloudTemplateOptions vOptions = VCloudTemplateOptions.class.cast(template.getOptions()); 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 = networkConfigurationForNetworkAndOptions.apply(networkToConnect, vOptions); // 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 description = VCloudTemplateOptions.class.cast(template.getOptions()).getDescription(); if (description == null) { Map md = metadataAndTagsAsCommaDelimitedValue(template.getOptions()); description = Joiner.on('\n').withKeyValueSeparator("=").join(md); } options.description(description); options.deploy(false); options.powerOn(false); URI VDC = URI.create(template.getLocation().getId()); logger.debug(">> instantiating vApp vDC(%s) template(%s) name(%s) options(%s) ", VDC, templateId, name, options); VApp vAppResponse = client.getVAppTemplateApi().createVAppInVDCByInstantiatingTemplate(name, VDC, templateId, options); return vAppResponse; } // TODO: filtering on "none" is a hack until we can filter on // vAppTemplate.getNetworkConfigSection().getNetworkConfigs() where // name = getChildren().NetworkConnectionSection.connection where ipallocationmode == none static Predicate networkWithNoIpAllocation = new Predicate() { @Override public boolean apply(Network input) { return "none".equals(input.getName()); } }; public void waitForTask(Task task) { if (!successTester.apply(task.getHref())) { throw new TaskStillRunningException(task); } } /** * 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(); 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.getVmApi().updateGuestCustomizationOfVm(guestConfiguration, vm.getHref()); } 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(); checkArgument(net.getConnections().size() > 0, "no connections on vm %s", vm); NetworkConnection toConnect = findWithPoolAllocationOrFirst(net); 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.getVmApi().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) { return client.getVmApi().updateCPUCountOfVm(cpuCount, vm.getHref()); } public Task updateMemoryMBOfVm(Vm vm, int memoryInMB) { return client.getVmApi().updateMemoryMBOfVm(memoryInMB, vm.getHref()); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy