Java tutorial
/** * Copyright (C) 2009-2015 Dell, Inc * * ==================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ==================================================================== */ package org.dasein.cloud.vcloud.compute; import org.apache.log4j.Logger; import org.dasein.cloud.CloudException; import org.dasein.cloud.InternalException; import org.dasein.cloud.Tag; import org.dasein.cloud.compute.AbstractVMSupport; import org.dasein.cloud.compute.Architecture; import org.dasein.cloud.compute.MachineImage; import org.dasein.cloud.compute.Platform; import org.dasein.cloud.compute.VMLaunchOptions; import org.dasein.cloud.compute.VirtualMachine; import org.dasein.cloud.compute.VirtualMachineCapabilities; import org.dasein.cloud.compute.VirtualMachineProduct; import org.dasein.cloud.compute.VirtualMachineProductFilterOptions; import org.dasein.cloud.compute.VmState; import org.dasein.cloud.dc.DataCenter; import org.dasein.cloud.network.IPVersion; import org.dasein.cloud.network.RawAddress; import org.dasein.cloud.network.VLAN; import org.dasein.cloud.util.APITrace; import org.dasein.cloud.util.Cache; import org.dasein.cloud.util.CacheLevel; import org.dasein.cloud.util.TagUtils; import org.dasein.cloud.vcloud.vCloud; import org.dasein.cloud.vcloud.vCloudException; import org.dasein.cloud.vcloud.vCloudMethod; import org.dasein.util.Jiterator; import org.dasein.util.JiteratorPopulator; import org.dasein.util.PopulatorThread; import org.dasein.util.uom.storage.Gigabyte; import org.dasein.util.uom.storage.Megabyte; import org.dasein.util.uom.storage.Storage; import org.dasein.util.uom.time.Day; import org.dasein.util.uom.time.TimePeriod; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.TreeSet; import java.util.UUID; /** * Implements services for interacting with virtual machines in a vCloud environment. A Dasein Cloud virtual machine * maps to a VM running inside a vApp in vCloud. * <p>Created by George Reese: 9/17/12 10:58 AM</p> * @author George Reese * @author Erik Johnson * @author Tim Freeman * @version 2013.07 * @since 2013.04 */ public class vAppSupport extends AbstractVMSupport<vCloud> { static private final Logger logger = vCloud.getLogger(vAppSupport.class); static public final String PARENT_VAPP_ID = "parentVAppId"; private volatile transient VMSupportCapabilities capabilities; vAppSupport(@Nonnull vCloud provider) { super(provider); } public void deploy(@Nonnull String vmId) throws CloudException, InternalException { APITrace.begin(getProvider(), "VM.deploy"); try { vCloudMethod method = new vCloudMethod(getProvider()); String xml = method.get("vApp", vmId); if (xml != null) { Document doc = method.parseXML(xml); String docElementTagName = doc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); NodeList nodes = doc.getElementsByTagName(nsString + "VApp"); for (int i = 0; i < nodes.getLength(); i++) { NodeList links = nodes.item(i).getChildNodes(); for (int j = 0; j < links.getLength(); j++) { Node node = links.item(j); if (node.getNodeName().contains(":")) nsString = node.getNodeName().substring(0, node.getNodeName().indexOf(":") + 1); else nsString = ""; if (node.getNodeName().equalsIgnoreCase(nsString + "Link") && node.hasAttributes()) { Node rel = node.getAttributes().getNamedItem("rel"); if (rel != null && rel.getNodeValue().trim().equalsIgnoreCase("deploy")) { Node href = node.getAttributes().getNamedItem("href"); if (href != null) { String endpoint = href.getNodeValue().trim(); String action = method.getAction(endpoint); StringBuilder payload = new StringBuilder(); payload.append( "<DeployVAppParams powerOn=\"false\" xmlns=\"http://www.vmware.com/vcloud/v1.5\"/>"); method.waitFor(method.post(action, endpoint, method.getMediaTypeForActionDeployVApp(), payload.toString())); break; } } } } } } } finally { APITrace.end(); } } @Nonnull @Override public VirtualMachineCapabilities getCapabilities() throws InternalException, CloudException { if (capabilities == null) { capabilities = new VMSupportCapabilities(getProvider()); } return capabilities; } public @Nullable VirtualMachineProduct getProduct(@Nonnull String productId) throws InternalException, CloudException { APITrace.begin(getProvider(), "VM.getProduct"); try { VirtualMachineProduct product = super.getProduct(productId); if (product == null && productId.startsWith("custom")) { String[] parts = productId.split(":"); product = new VirtualMachineProduct(); product.setProviderProductId(productId); if (parts.length == 3) { product.setCpuCount(Integer.parseInt(parts[1])); product.setRamSize(new Storage<Megabyte>(Integer.parseInt(parts[2]), Storage.MEGABYTE)); } else { product.setCpuCount(1); product.setRamSize(new Storage<Megabyte>(512, Storage.MEGABYTE)); } product.setName(productId); product.setDescription(productId); } return product; } finally { APITrace.end(); } } private @Nullable String getVDC(@Nonnull String vappId) throws CloudException, InternalException { vCloudMethod method = new vCloudMethod(getProvider()); String xml = method.get("vApp", vappId); if (xml == null || xml.equals("")) { return null; } Document doc = method.parseXML(xml); String docElementTagName = doc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); NodeList nodes = doc.getElementsByTagName(nsString + "VApp"); if (nodes.getLength() < 1) { return null; } Node node = nodes.item(0); NodeList elements = node.getChildNodes(); for (int i = 0; i < elements.getLength(); i++) { Node n = elements.item(i); if (n.getNodeName().contains(":")) nsString = n.getNodeName().substring(0, n.getNodeName().indexOf(":") + 1); else nsString = ""; if (n.getNodeName().equalsIgnoreCase(nsString + "Link") && n.hasAttributes()) { Node rel = n.getAttributes().getNamedItem("rel"); if (rel != null && rel.getNodeValue().trim().equals("up")) { Node type = n.getAttributes().getNamedItem("type"); if (type != null && type.getNodeValue().trim().equals(method.getMediaTypeForVDC())) { Node href = n.getAttributes().getNamedItem("href"); if (href != null) { return getProvider().toID(href.getNodeValue().trim()); } } } } } return null; } @Override public VirtualMachine getVirtualMachine(@Nonnull String vmId) throws InternalException, CloudException { APITrace.begin(getProvider(), "VM.getVirtualMachine"); try { vCloudMethod method = new vCloudMethod(getProvider()); String xml = method.get("vApp", vmId); if (xml != null && !xml.equals("")) { Document doc = method.parseXML(xml); String docElementTagName = doc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); NodeList vmNodes = doc.getElementsByTagName(nsString + "Vm"); if (vmNodes.getLength() < 1) { return null; } Node vmNode = vmNodes.item(0); NodeList vmElements = vmNode.getChildNodes(); String vdc = null, parentVapp = null; for (int i = 0; i < vmElements.getLength(); i++) { Node n = vmElements.item(i); if (n.getNodeName().contains(":")) nsString = n.getNodeName().substring(0, n.getNodeName().indexOf(":") + 1); else nsString = ""; if (n.getNodeName().equalsIgnoreCase(nsString + "Link") && n.hasAttributes()) { Node rel = n.getAttributes().getNamedItem("rel"); if (rel != null && rel.getNodeValue().trim().equals("up")) { Node type = n.getAttributes().getNamedItem("type"); if (type != null && type.getNodeValue().trim().equals(method.getMediaTypeForVApp())) { Node href = n.getAttributes().getNamedItem("href"); if (href != null) { parentVapp = getProvider().toID(href.getNodeValue().trim()); vdc = getVDC(parentVapp); } } } } } if (vdc != null) { return toVirtualMachine(vdc, parentVapp, vmNode, getProvider().getNetworkServices().getVlanSupport().listVlans()); } } return null; } finally { APITrace.end(); } } @Override public boolean isSubscribed() throws CloudException, InternalException { APITrace.begin(getProvider(), "VM.isSubscribed"); try { return (getProvider().testContext() != null); } finally { APITrace.end(); } } @Override public @Nonnull VirtualMachine launch(@Nonnull final VMLaunchOptions withLaunchOptions) throws CloudException, InternalException { APITrace.begin(getProvider(), "launchVM"); final String pw = withLaunchOptions.getBootstrapPassword(); try { final String fullname = withLaunchOptions.getHostName(); final String basename = validateHostName(withLaunchOptions.getHostName()); if (basename.length() > 27) { throw new CloudException( "The maximum name length is 27: '" + basename + "' is " + basename.length()); } String vdcId = withLaunchOptions.getDataCenterId(); if (vdcId == null) { for (DataCenter dc : getProvider().getDataCenterServices() .listDataCenters(getContext().getRegionId())) { if (dc.isActive() && dc.isAvailable()) { vdcId = dc.getProviderDataCenterId(); break; } } } if (vdcId == null) { throw new CloudException("Unable to identify a target data center for deploying VM"); } final VirtualMachineProduct product = getProduct(withLaunchOptions.getStandardProductId()); final vCloudMethod method = new vCloudMethod(getProvider()); final MachineImage img = getProvider().getComputeServices().getImageSupport() .getImage(withLaunchOptions.getMachineImageId()); if (img == null) { throw new CloudException("No such image: " + withLaunchOptions.getMachineImageId()); } StringBuilder xml = new StringBuilder(); xml.append( "<InstantiateVAppTemplateParams xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"") .append(withLaunchOptions.getFriendlyName()) .append("\" xmlns=\"http://www.vmware.com/vcloud/v1.5\" deploy=\"false\" powerOn=\"false\">"); xml.append("<Description>").append(img.getProviderMachineImageId()).append("</Description>"); String vlanId = withLaunchOptions.getVlanId(); // If vlanId is not specified, explicitly use default in machine image. If left out, // default is not recognized in vCloud 1.5, error is: VCD entity network "X" // specified for VM "Y" does not exist (even though it does exist) if (vlanId == null || vlanId.trim().isEmpty()) { String defaultVlanName = (String) img.getTag("defaultVlanName"); String defaultVlanNameDHCP = (String) img.getTag("defaultVlanNameDHCP"); if (defaultVlanName != null && !defaultVlanName.trim().isEmpty()) { Iterable<VLAN> vlans = getProvider().getNetworkServices().getVlanSupport().listVlans(); for (VLAN vlan : vlans) { if (defaultVlanName.equalsIgnoreCase(vlan.getName())) { vlanId = vlan.getProviderVlanId(); } } if (vlanId == null) { throw new CloudException("Could not locate default vlan '" + defaultVlanName + "'"); } } else if (defaultVlanNameDHCP != null && !defaultVlanNameDHCP.trim().isEmpty()) { throw new CloudException( "No vlan selected and the default is DHCP-based which is not supported"); } else { throw new CloudException("No vlan specified and no default."); } } final VLAN vlan = getProvider().getNetworkServices().getVlanSupport().getVlan(vlanId); if (vlan != null) { //check image tags String parentName = null, parentId = null, parentHref = null; if (img.getTag("parentNetworkName") != null) { parentName = img.getTag("parentNetworkName").toString(); } if (img.getTag("parentNetworkId") != null) { parentId = img.getTag("parentNetworkId").toString(); } if (img.getTag("parentNetworkHref") != null) { parentHref = img.getTag("parentNetworkHref").toString(); if (parentHref.length() > 0) { parentHref = parentHref.substring(0, parentHref.indexOf("/network/") + 9); } else { logger.debug( "Not found network settings in the template so getting the base href from network"); parentHref = vlan.getTag("networkHref").toString(); parentHref = vlan.getTag("networkHref").toString().substring(0, parentHref.indexOf("/network/") + 9); } } else { logger.debug( "Not found network settings in the template so getting the base href from network"); parentHref = vlan.getTag("networkHref").toString(); parentHref = vlan.getTag("networkHref").toString().substring(0, parentHref.indexOf("/network/") + 9); } if (parentName == null || !vlan.getName().equals(parentName)) { // if we don't have the parent id we need to try and find it if (parentId == null && parentName != null) { Iterable<VLAN> vlanList = getProvider().getNetworkServices().getVlanSupport().listVlans(); while (vlanList.iterator().hasNext()) { VLAN v = vlanList.iterator().next(); if (v.getName().equals(parentName)) { // found a match parentId = v.getProviderVlanId(); break; } } if (parentId == null || parentHref == null) { throw new CloudException( "Unable to find the network config settings - cannot specify network for this vApp"); } } // new vapp network config xml.append("<InstantiationParams>"); xml.append("<NetworkConfigSection>"); xml.append( "<Info xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\">Configuration parameters for logical networks</Info>"); xml.append("<NetworkConfig networkName=\"").append(vCloud.escapeXml(vlan.getName())) .append("\">"); xml.append("<Configuration>"); xml.append("<ParentNetwork name=\"").append(vCloud.escapeXml(vlan.getName())).append("\""); xml.append(" id=\"").append(vlanId).append("\""); xml.append(" href=\"").append(parentHref).append(vlanId).append("\"/>"); xml.append("<FenceMode>bridged</FenceMode>"); xml.append("</Configuration>"); xml.append("</NetworkConfig>"); if (parentName != null) { //existing network config from vapp template xml.append("<NetworkConfig networkName=\"").append(parentName).append("\">"); xml.append("<Configuration>"); xml.append("<ParentNetwork name=\"").append(parentName).append("\""); xml.append(" id=\"").append(parentId).append("\""); xml.append(" href=\"").append(parentHref).append(parentId).append("\"/>"); xml.append("<FenceMode>bridged</FenceMode>"); xml.append("</Configuration>"); xml.append("</NetworkConfig>"); } else if (img.getTag("fullNetConf") != null && img.getTag("fullNetConf").toString().length() > 0) { xml.append(img.getTag("fullNetConf")); } xml.append("</NetworkConfigSection>"); xml.append("</InstantiationParams>"); } String vAppTemplateUrl = method.toURL("vAppTemplate", img.getProviderMachineImageId()); xml.append("<Source href=\"").append(vAppTemplateUrl).append("\"/>"); } else { throw new CloudException("Failed to find vlan " + vlanId); } xml.append("<AllEULAsAccepted>true</AllEULAsAccepted>"); xml.append("</InstantiateVAppTemplateParams>"); if (logger.isDebugEnabled()) { try { method.parseXML(xml.toString()); logger.debug("XML passes"); } catch (Throwable t) { logger.error("XML parse failure: " + t.getMessage()); } } String instantiateResponse = method.post(vCloudMethod.INSTANTIATE_VAPP, vdcId, xml.toString()); try { method.waitFor(instantiateResponse); } catch (CloudException e) { logger.error("Error waiting for " + vCloudMethod.INSTANTIATE_VAPP + " task to complete", e); throw new CloudException( "Error waiting for " + vCloudMethod.INSTANTIATE_VAPP + " task to complete"); } Document composeDoc = method.parseXML(instantiateResponse); String docElementTagName = composeDoc.getDocumentElement().getTagName(); final String nsString; if (docElementTagName.contains(":")) { nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); } else { nsString = ""; } NodeList vapps = composeDoc.getElementsByTagName(nsString + "VApp"); if (vapps.getLength() < 1) { throw new CloudException("The instantiation operation succeeded, but no vApp was present"); } Node vapp = vapps.item(0); Node href = vapp.getAttributes().getNamedItem("href"); String vappId = getProvider().toID(href.getNodeValue().trim()); String vAppResponse = method.get("vApp", vappId); if (vAppResponse == null) { try { undeploy(vappId); method.delete("vApp", vappId); } catch (Throwable t) { logger.error("Problem backing out after vApp went away: " + t.getMessage()); } throw new CloudException("vApp went away"); } final Document doc = method.parseXML(vAppResponse); NodeList vmNodes = doc.getElementsByTagName(nsString + "Vm"); // vCloud has a 27 character limit on computer-name, reject upfront final boolean multipleVMs = (vmNodes.getLength() > 1); if (multipleVMs) { // take suffixes into account: if (basename.length() > 25) { try { vCloudMethod dmethod = new vCloudMethod(getProvider()); dmethod.delete("vApp", vappId); } catch (Throwable t) { logger.error("Problem cleaning up vApp " + vappId + ": " + t.getMessage()); } throw new CloudException( "Because there are multiple VMs in this vApp, the maximum name length is 25: '" + basename + "' is " + basename.length()); } if (fullname.length() > 126) { try { vCloudMethod dmethod = new vCloudMethod(getProvider()); dmethod.delete("vApp", vappId); } catch (Throwable t) { logger.error("Problem cleaning up vApp " + vappId + ": " + t.getMessage()); } throw new CloudException( "Because there are multiple VMs in this vApp, the maximum name length is 126: '" + basename + "' is " + basename.length()); } } else if (basename.length() > 27) { // should have been rejected already throw new CloudException( "The maximum name length is 27: '" + basename + "' is " + basename.length()); } else if (fullname.length() > 128) { throw new CloudException( "The maximum name length is 128: '" + basename + "' is " + basename.length()); } String vmId = parseVmId(vmNodes); if (vmId == null) { //Sometimes the vApp response comes back before the VM is included in it //Attempting a single (for the moment) retry in this case but may want to add a loop (potentially doing Thread.sleep) around the retry logger.error("Grabbed the vApp response before the VM was included - retrying"); vmId = retryListvApp(method, vappId, nsString); if (vmId == null) { try { undeploy(vappId); method.delete("vApp", vappId); } catch (Throwable t) { logger.error("Problem backing out after no virtual machines exist in response: " + t.getMessage()); } throw new CloudException("No virtual machines exist in response"); } } VirtualMachine vm = getVirtualMachine(vmId); if (vm == null) { try { undeploy(vappId); method.delete("vApp", vappId); } catch (Throwable t) { logger.error("Problem backing out after failing to identify VM in response: " + t.getMessage()); } throw new CloudException("Unable to identify VM " + vmId + "."); } final String fvmId = vmId; Thread t = new Thread() { public void run() { try { Map<String, Object> metadata = withLaunchOptions.getMetaData(); if (metadata == null) { metadata = new HashMap<String, Object>(); } metadata.put("dsnImageId", img.getProviderMachineImageId()); metadata.put("dsnCreated", String.valueOf(System.currentTimeMillis())); method.postMetaData("vApp", fvmId, metadata); } catch (Throwable warn) { logger.warn("Error updating meta-data on launch: " + warn.getMessage()); } NodeList vapps = doc.getElementsByTagName(nsString + "VApp"); if (vapps.getLength() < 1) { logger.error("The instantiation operation succeeded, but no vApp was present"); } Node vapp = vapps.item(0); Node href = vapp.getAttributes().getNamedItem("href"); if (href != null) { String vappId = getProvider().toID(href.getNodeValue().trim()); String vAppResponse; try { vAppResponse = method.get("vApp", vappId); } catch (CloudException e) { logger.error("Error getting vApp " + vappId, e); return; } catch (InternalException e) { logger.error("Error getting vApp " + vappId, e); return; } if (vAppResponse == null || vAppResponse.equals("")) { logger.error("vApp " + vappId + " went away"); } Document vAppDoc; try { vAppDoc = method.parseXML(vAppResponse); } catch (CloudException e) { logger.error("Error parsing vApp " + vappId + " xml: ", e); return; } catch (InternalException e) { logger.error("Error parsing vApp " + vappId + " xml: ", e); return; } String docElementTagName = vAppDoc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); vapps = vAppDoc.getElementsByTagName(nsString + "VApp"); if (vapps.getLength() < 1) { logger.error("No VApp in vApp request for " + vappId); } vapp = vapps.item(0); NodeList tasks = vapp.getChildNodes(); for (int i = 0; i < tasks.getLength(); i++) { Node task = tasks.item(i); if (task.getNodeName().contains(":")) nsString = task.getNodeName().substring(0, task.getNodeName().indexOf(":") + 1); else nsString = ""; if (task.getNodeName().equalsIgnoreCase(nsString + "Task")) { href = task.getAttributes().getNamedItem("href"); if (href != null) { try { method.waitFor(href.getNodeValue().trim()); } catch (CloudException e) { logger.error("Error waiting for task to complete.", e); } } } } String vAppGetResponse; try { vAppGetResponse = method.get("vApp", vappId); } catch (CloudException e) { logger.error("Error getting vApp " + vappId, e); return; } catch (InternalException e) { logger.error("Error getting vApp " + vappId, e); return; } if (vAppGetResponse == null) { logger.error("vApp went away"); } try { vAppDoc = method.parseXML(vAppGetResponse); } catch (CloudException e) { logger.error("Error parsing vApp " + vappId + " xml: ", e); return; } catch (InternalException e) { logger.error("Error parsing vApp " + vappId + " xml: ", e); return; } docElementTagName = vAppDoc.getDocumentElement().getTagName(); nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); vapps = vAppDoc.getElementsByTagName(nsString + "VApp"); if (vapps.getLength() < 1) { logger.error("vApp went away"); } vapp = vapps.item(0); NodeList attributes = vapp.getChildNodes(); String vmId = null; for (int i = 0; i < attributes.getLength(); i++) { Node attribute = attributes.item(i); if (attribute.getNodeName().contains(":")) nsString = attribute.getNodeName().substring(0, attribute.getNodeName().indexOf(":") + 1); else nsString = ""; if (attribute.getNodeName().equals(nsString + "Children") && attribute.hasChildNodes()) { NodeList children = attribute.getChildNodes(); int count = 1; for (int j = 0; j < children.getLength(); j++) { Node vm = children.item(j); if (vm.getNodeName().contains(":")) nsString = vm.getNodeName().substring(0, vm.getNodeName().indexOf(":") + 1); else nsString = ""; if (vm.getNodeName().equalsIgnoreCase(nsString + "Vm") && vm.hasAttributes()) { href = vm.getAttributes().getNamedItem("href"); if (href != null) { String suffix = (multipleVMs ? ("-" + count) : ""); count++; String vmUrl = href.getNodeValue().trim(); vmId = getProvider().toID(vmUrl); StringBuilder guestXml = new StringBuilder(); guestXml.append( "<GuestCustomizationSection xmlns=\"http://www.vmware.com/vcloud/v1.5\" "); guestXml.append( " xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" ovf:required=\"false\">"); guestXml.append( "<Info xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\">Specifies Guest OS Customization Settings</Info>"); guestXml.append("<Enabled>true</Enabled>"); guestXml.append("<ChangeSid>") .append(String.valueOf(img.getPlatform().isWindows())) .append("</ChangeSid>"); guestXml.append("<VirtualMachineId>") .append(UUID.randomUUID().toString()) .append("</VirtualMachineId>"); guestXml.append("<JoinDomainEnabled>false</JoinDomainEnabled>"); guestXml.append("<UseOrgSettings>false</UseOrgSettings>"); guestXml.append("<AdminPasswordEnabled>true</AdminPasswordEnabled>"); if (pw != null) { guestXml.append("<AdminPassword>").append(vCloud.escapeXml(pw)) .append("</AdminPassword>"); //guestXml.append("<AdminPasswordAuto>false</AdminPasswordAuto>"); } else { guestXml.append("<AdminPasswordAuto>true</AdminPasswordAuto>"); } guestXml.append("<ResetPasswordRequired>false</ResetPasswordRequired>"); String userData = withLaunchOptions.getUserData(); if (userData != null && userData.length() > 0) { guestXml.append("<CustomizationScript>") .append(vCloud.escapeXml(userData)) .append("</CustomizationScript>"); } else { String customizationScript = parseCustomizationScript(vm); if (customizationScript != null) { guestXml.append("<CustomizationScript>") .append(vCloud.escapeXml(customizationScript)) .append("</CustomizationScript>"); } } guestXml.append("<ComputerName>") .append(vCloud.escapeXml(validateHostName( withLaunchOptions.getHostName() + suffix))) .append("</ComputerName>"); guestXml.append("</GuestCustomizationSection>"); try { method.waitFor(method.put("guestCustomizationSection", vmUrl + "/guestCustomizationSection", method.getMediaTypeForGuestCustomizationSection(), guestXml.toString())); } catch (CloudException e) { logger.error("Error configuring guest for vApp " + vappId, e); return; } catch (InternalException e) { logger.error("Error configuring guest for vApp " + vappId, e); return; } StringBuilder vmXml = new StringBuilder(); vmXml.append( "<vcloud:Vm xmlns:vcloud=\"http://www.vmware.com/vcloud/v1.5\" "); vmXml.append("name=\"").append(vCloud.escapeXml(fullname + suffix)) .append("\">"); vmXml.append("<vcloud:Description>") .append(withLaunchOptions.getDescription()) .append("</vcloud:Description>"); vmXml.append("</vcloud:Vm>"); try { method.waitFor(method.put("", vmUrl, method.getMediaTypeForVM(), vmXml.toString())); } catch (CloudException e) { logger.error("Error configuring vm for vApp " + vappId, e); return; } catch (InternalException e) { logger.error("Error configuring vm for vApp " + vappId, e); return; } if (product != null) { StringBuilder xml = new StringBuilder(); xml.append("<vcloud:Item " + "xmlns:vcloud=\"http://www.vmware.com/vcloud/v1.5\" " + "xmlns:rasd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData\" " + "vcloud:type=\"application/vnd.vmware.vcloud.rasdItem+xml\" " + "vcloud:href=\"").append(vmUrl) .append("/virtualHardwareSection/cpu\">"); xml.append( "<rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>"); xml.append( "<rasd:Description>Number of Virtual CPUs</rasd:Description>"); xml.append("<rasd:ElementName>") .append(String.valueOf(product.getCpuCount())) .append(" virtual CPU(s)</rasd:ElementName>"); xml.append("<rasd:InstanceID>1</rasd:InstanceID>"); xml.append("<rasd:Reservation>0</rasd:Reservation>"); xml.append("<rasd:ResourceType>3</rasd:ResourceType>"); xml.append("<rasd:VirtualQuantity>") .append(String.valueOf(product.getCpuCount())) .append("</rasd:VirtualQuantity>"); xml.append("<rasd:Weight>") .append(String.valueOf(product.getCpuCount() * 1000)) .append("</rasd:Weight>"); //changed from 0 xml.append("<vcloud:Link href=\"").append(vmUrl).append( "/virtualHardwareSection/cpu\" rel=\"edit\" type=\"application/vnd.vmware.vcloud.rasdItem+xml\"/>"); xml.append("</vcloud:Item>"); try { method.waitFor(method.put("virtualHardwareSection/cpu", vmUrl + "/virtualHardwareSection/cpu", method.getMediaTypeForRasdItem(), xml.toString())); } catch (CloudException e) { logger.error("Error configuring virtual hardware cpu for vApp " + vappId, e); return; } catch (InternalException e) { logger.error("Error configuring virtual hardware cpu for vApp " + vappId, e); return; } xml = new StringBuilder(); xml.append("<vcloud:Item " + "xmlns:vcloud=\"http://www.vmware.com/vcloud/v1.5\" " + "xmlns:rasd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData\" " + "vcloud:type=\"application/vnd.vmware.vcloud.rasdItem+xml\" " + "vcloud:href=\"").append(vmUrl) .append("/virtualHardwareSection/memory\">"); xml.append( "<rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>"); xml.append("<rasd:Description>Memory Size</rasd:Description>"); xml.append("<rasd:ElementName>") .append(product.getRamSize().toString()) .append("</rasd:ElementName>"); xml.append("<rasd:InstanceID>2</rasd:InstanceID>"); xml.append("<rasd:Reservation>0</rasd:Reservation>"); xml.append("<rasd:ResourceType>4</rasd:ResourceType>"); xml.append("<rasd:VirtualQuantity>") .append(String.valueOf(product.getRamSize().intValue())) .append("</rasd:VirtualQuantity>"); xml.append("<rasd:Weight>") .append(String .valueOf(product.getRamSize().intValue() * 10)) .append("</rasd:Weight>"); xml.append("<vcloud:Link href=\"").append(vmUrl).append( "/virtualHardwareSection/memory\" rel=\"edit\" type=\"application/vnd.vmware.vcloud.rasdItem+xml\"/>"); xml.append("</vcloud:Item>"); try { method.waitFor(method.put("virtualHardwareSection/memory", vmUrl + "/virtualHardwareSection/memory", method.getMediaTypeForRasdItem(), xml.toString())); } catch (CloudException e) { logger.error( "Error configuring virtual hardware memory for vApp " + vappId, e); return; } catch (InternalException e) { logger.error( "Error configuring virtual hardware memory for vApp " + vappId, e); return; } if (vlan != null) { xml = new StringBuilder(); xml.append("<NetworkConnectionSection href=\"").append(vmUrl) .append("/networkConnectionSection/").append("\" "); xml.append("xmlns=\"http://www.vmware.com/vcloud/v1.5\" "); xml.append(" type=\"") .append(method .getMediaTypeForNetworkConnectionSection()) .append("\">"); xml.append( "<Info xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\">Specifies the available VM network connections</Info>"); xml.append( "<PrimaryNetworkConnectionIndex>0</PrimaryNetworkConnectionIndex>"); xml.append("<NetworkConnection network=\"") .append(vCloud.escapeXml(vlan.getName())).append("\">"); xml.append( "<NetworkConnectionIndex>0</NetworkConnectionIndex>"); xml.append("<IsConnected>true</IsConnected>"); xml.append( "<IpAddressAllocationMode>POOL</IpAddressAllocationMode>"); xml.append("</NetworkConnection>"); xml.append("</NetworkConnectionSection>"); try { method.waitFor(method.put("networkConnectionSection", vmUrl + "/networkConnectionSection", method.getMediaTypeForNetworkConnectionSection(), xml.toString())); } catch (CloudException e) { logger.error("Error configuring virtual hardware for vApp " + vappId, e); return; } catch (InternalException e) { logger.error("Error configuring virtual hardware for vApp " + vappId, e); return; } } } break; } } } } if (vmId != null) { break; } } if (vmId == null) { logger.error("No virtual machines exist in " + vappId); } try { deploy(vappId); } catch (CloudException e) { logger.error("Error deploying vApp " + vappId, e); return; } catch (InternalException e) { logger.error("Error deploying vApp " + vappId, e); return; } try { startVapp(vappId, true); } catch (CloudException e) { logger.error("Error starting vApp " + vappId, e); } catch (InternalException e) { logger.error("Error starting vApp " + vappId, e); } } } }; t.setName("Configure vCloud VM " + vm.getProviderVirtualMachineId()); t.setDaemon(true); t.start(); vm.setProviderMachineImageId(img.getProviderMachineImageId()); if (pw != null) { vm.setRootPassword(pw); } return vm; } finally { APITrace.end(); } } private String parseVmId(NodeList vmNodes) { String vmId = ""; Node vmNode = vmNodes.item(0); if (vmNode != null && vmNode.hasAttributes()) { Node vmHref = vmNode.getAttributes().getNamedItem("href"); if (vmHref != null) { String vmUrl = vmHref.getNodeValue().trim(); vmId = getProvider().toID(vmUrl); } else { vmId = null; } } else { vmId = null; } return vmId; } private String retryListvApp(vCloudMethod method, String vappId, String nsString) throws CloudException, InternalException { String retryResponse = method.get("vApp", vappId); final Document retryDoc = method.parseXML(retryResponse); String vmId = parseVmId(retryDoc.getElementsByTagName(nsString + "Vm")); return vmId; } private String parseCustomizationScript(@Nonnull Node vm) { NodeList attributes = vm.getChildNodes(); for (int i = 0; i < attributes.getLength(); i++) { Node attribute = attributes.item(i); if (attribute.getNodeName().equalsIgnoreCase("GuestCustomizationSection") && attribute.hasChildNodes()) { NodeList elements = attribute.getChildNodes(); for (int j = 0; j < elements.getLength(); j++) { Node element = elements.item(j); if (element.getNodeName().equalsIgnoreCase("CustomizationScript") && element.hasChildNodes()) { String customizationScript = element.getFirstChild().getNodeValue().trim(); if (customizationScript != null) { return customizationScript; } } } } } return null; } @Override public @Nonnull Iterable<String> listFirewalls(@Nonnull String vmId) throws InternalException, CloudException { return Collections.emptyList(); } @Override public @Nonnull Iterable<VirtualMachineProduct> listAllProducts() throws InternalException, CloudException { return listProducts(null, VirtualMachineProductFilterOptions.getInstance()); } @Nonnull public Iterable<VirtualMachineProduct> listProducts(@Nonnull String providerMachineImageId, @Nullable VirtualMachineProductFilterOptions options) throws InternalException, CloudException { APITrace.begin(getProvider(), "listVMProducts"); try { String cacheName = "productsALL"; if (options.getArchitecture() != null) { cacheName = "products" + options.getArchitecture().name(); } Cache<VirtualMachineProduct> cache = Cache.getInstance(getProvider(), cacheName, VirtualMachineProduct.class, CacheLevel.REGION, new TimePeriod<Day>(1, TimePeriod.DAY)); Iterable<VirtualMachineProduct> products = cache.get(getContext()); if (products == null) { ArrayList<VirtualMachineProduct> list = new ArrayList<VirtualMachineProduct>(); try { String resource = getProvider().getVMProductsResource(); InputStream input = vAppSupport.class.getResourceAsStream(resource); if (input != null) { BufferedReader reader = new BufferedReader(new InputStreamReader(input)); StringBuilder json = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { json.append(line); json.append("\n"); } JSONArray arr = new JSONArray(json.toString()); JSONObject toCache = null; for (int i = 0; i < arr.length(); i++) { JSONObject productSet = arr.getJSONObject(i); String cloud, provider; if (productSet.has("cloud")) { cloud = productSet.getString("cloud"); } else { continue; } if (productSet.has("provider")) { provider = productSet.getString("provider"); } else { continue; } if (!productSet.has("products")) { continue; } if (toCache == null || (provider.equals("default") && cloud.equals("default"))) { toCache = productSet; } if (provider.equalsIgnoreCase(getProvider().getProviderName()) && cloud.equalsIgnoreCase(getProvider().getCloudName())) { toCache = productSet; break; } } if (toCache == null) { logger.warn("No products were defined"); return Collections.emptyList(); } JSONArray plist = toCache.getJSONArray("products"); for (int i = 0; i < plist.length(); i++) { JSONObject product = plist.getJSONObject(i); boolean supported = false; // If architecture is specified, check if product matches if (options != null && options.getArchitecture() != null && product.has("architectures")) { JSONArray architectures = product.getJSONArray("architectures"); for (int j = 0; j < architectures.length(); j++) { String a = architectures.getString(j); if (options.getArchitecture().name().equals(a)) { supported = true; break; } } if (!supported) { continue; } } else { // No architecture specified, flip the flag - all architectures allowed supported = true; } if (product.has("excludesRegions")) { JSONArray regions = product.getJSONArray("excludesRegions"); for (int j = 0; j < regions.length(); j++) { String r = regions.getString(j); if (r.equals(getContext().getRegionId())) { supported = false; break; } } } if (!supported) { continue; } VirtualMachineProduct prd = toProduct(product); if (prd != null) { if (options != null) { // Filter supplied, add matches only. if (options.matches(prd)) { list.add(prd); } } else { // No filter supplied, add all survived. list.add(prd); } } } } else { logger.warn("No standard products resource exists for " + resource); } products = list; cache.put(getContext(), products); } catch (IOException e) { throw new InternalException(e); } catch (JSONException e) { throw new InternalException(e); } } return products; } finally { APITrace.end(); } } @Override public Iterable<Architecture> listSupportedArchitectures() throws InternalException, CloudException { Cache<Architecture> cache = Cache.getInstance(getProvider(), "architectures", Architecture.class, CacheLevel.CLOUD); Iterable<Architecture> list = cache.get(getContext()); if (list == null) { ArrayList<Architecture> a = new ArrayList<Architecture>(); a.add(Architecture.I32); a.add(Architecture.I64); list = a; cache.put(getContext(), Collections.unmodifiableList(a)); } return list; } @Override public @Nonnull Iterable<VirtualMachine> listVirtualMachines() throws InternalException, CloudException { getProvider().hold(); PopulatorThread<VirtualMachine> populator = new PopulatorThread<VirtualMachine>( new JiteratorPopulator<VirtualMachine>() { @Override public void populate(@Nonnull Jiterator<VirtualMachine> iterator) throws Exception { try { APITrace.begin(getProvider(), "VM.listVirtualMachines"); try { Iterable<VLAN> vlans = getProvider().getNetworkServices().getVlanSupport() .listVlans(); vCloudMethod method = new vCloudMethod(getProvider()); for (DataCenter dc : method.listDataCenters()) { String xml = method.get("vdc", dc.getProviderDataCenterId()); if (xml != null && !xml.equals("")) { Document doc = method.parseXML(xml); String docElementTagName = doc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); NodeList vdcs = doc.getElementsByTagName(nsString + "Vdc"); if (vdcs.getLength() > 0) { NodeList attributes = vdcs.item(0).getChildNodes(); for (int i = 0; i < attributes.getLength(); i++) { Node attribute = attributes.item(i); if (attribute.getNodeName().contains(":")) nsString = attribute.getNodeName().substring(0, attribute.getNodeName().indexOf(":") + 1); else nsString = ""; if (attribute.getNodeName() .equalsIgnoreCase(nsString + "ResourceEntities") && attribute.hasChildNodes()) { NodeList resources = attribute.getChildNodes(); for (int j = 0; j < resources.getLength(); j++) { Node resource = resources.item(j); if (resource.getNodeName() .equalsIgnoreCase(nsString + "ResourceEntity") && resource.hasAttributes()) { Node type = resource.getAttributes() .getNamedItem("type"); if (type != null && type.getNodeValue().equalsIgnoreCase( method.getMediaTypeForVApp())) { Node href = resource.getAttributes() .getNamedItem("href"); loadVmsFor(dc.getProviderDataCenterId(), getProvider() .toID(href.getNodeValue().trim()), iterator, vlans); } } } } } } } } } finally { APITrace.end(); } } finally { getProvider().release(); } } }); populator.populate(); return populator.getResult(); } private void loadVmsFor(@Nonnull String vdcId, @Nonnull String id, @Nonnull Jiterator<VirtualMachine> vms, @Nonnull Iterable<VLAN> vlans) throws InternalException, CloudException { vCloudMethod method = new vCloudMethod(getProvider()); String xml = method.get("vApp", id); if (xml == null || xml.equals("")) { return; } Document doc = method.parseXML(xml); String docElementTagName = doc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); NodeList vapps = doc.getElementsByTagName(nsString + "VApp"); if (vapps.getLength() < 1) { return; } NodeList attributes = vapps.item(0).getChildNodes(); for (int i = 0; i < attributes.getLength(); i++) { Node attribute = attributes.item(i); if (attribute.getNodeName().contains(":")) nsString = attribute.getNodeName().substring(0, attribute.getNodeName().indexOf(":") + 1); else nsString = ""; if (attribute.getNodeName().equals(nsString + "Children") && attribute.hasChildNodes()) { NodeList children = attribute.getChildNodes(); for (int j = 0; j < children.getLength(); j++) { Node vmNode = children.item(j); if (vmNode.getNodeName().equalsIgnoreCase(nsString + "Vm") && vmNode.hasAttributes()) { VirtualMachine vm = toVirtualMachine(vdcId, id, vmNode, vlans); if (vm != null) { vms.push(vm); } } } } } } @Override public void reboot(@Nonnull String vmId) throws CloudException, InternalException { APITrace.begin(getProvider(), "VM.reboot"); try { vCloudMethod method = new vCloudMethod(getProvider()); String xml = method.get("vApp", vmId); if (xml != null) { Document doc = method.parseXML(xml); String docElementTagName = doc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); NodeList nodes = doc.getElementsByTagName(nsString + "VApp"); if (nodes.getLength() > 0) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (node.getNodeName().contains(":")) nsString = node.getNodeName().substring(0, node.getNodeName().indexOf(":") + 1); else nsString = ""; if (node.getNodeName().equalsIgnoreCase(nsString + "Link") && node.hasAttributes()) { Node rel = node.getAttributes().getNamedItem("rel"); if (rel != null && rel.getNodeValue().trim().equalsIgnoreCase("power:reboot")) { Node href = node.getAttributes().getNamedItem("href"); if (href != null) { String endpoint = href.getNodeValue().trim(); String action = method.getAction(endpoint); method.post(action, endpoint, null, null); break; } } } } } else { nodes = doc.getElementsByTagName(nsString + "Vm"); if (nodes.getLength() > 0) { Node vmNode = nodes.item(0); if (vmNode != null && vmNode.hasChildNodes()) { NodeList links = vmNode.getChildNodes(); for (int i = 0; i < links.getLength(); i++) { Node link = links.item(i); if (link.getNodeName().equalsIgnoreCase(nsString + "Link") && link.hasAttributes()) { Node rel = link.getAttributes().getNamedItem("rel"); if (rel != null && rel.getNodeValue().trim().equalsIgnoreCase("power:reboot")) { Node href = link.getAttributes().getNamedItem("href"); if (href != null) { String endpoint = href.getNodeValue().trim(); String action = method.getAction(endpoint); method.post(action, endpoint, null, null); break; } } } } } } } } } finally { APITrace.end(); } } @Override public void resume(@Nonnull String vmId) throws CloudException, InternalException { APITrace.begin(getProvider(), "VM.resume"); try { startVapp(vmId, true); } finally { APITrace.end(); } } @Override public void start(@Nonnull String vmId) throws CloudException, InternalException { APITrace.begin(getProvider(), "VM.start"); try { startVapp(vmId, true); } finally { APITrace.end(); } } private void startVapp(@Nonnull String vappId, boolean wait) throws CloudException, InternalException { vCloudMethod method = new vCloudMethod(getProvider()); String xml = method.get("vApp", vappId); if (xml != null) { Document doc = method.parseXML(xml); String docElementTagName = doc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); NodeList nodes = doc.getElementsByTagName(nsString + "VApp"); if (nodes.getLength() < 1) { nodes = doc.getElementsByTagName(nsString + "Vm"); } for (int i = 0; i < nodes.getLength(); i++) { NodeList links = nodes.item(i).getChildNodes(); for (int j = 0; j < links.getLength(); j++) { Node node = links.item(j); if (node.getNodeName().contains(":")) nsString = node.getNodeName().substring(0, node.getNodeName().indexOf(":") + 1); else nsString = ""; if (node.getNodeName().equalsIgnoreCase(nsString + "Link") && node.hasAttributes()) { Node rel = node.getAttributes().getNamedItem("rel"); if (rel != null && rel.getNodeValue().trim().equalsIgnoreCase("power:powerOn")) { Node href = node.getAttributes().getNamedItem("href"); if (href != null) { String endpoint = href.getNodeValue().trim(); String action = method.getAction(endpoint); String task = method.post(action, endpoint, null, null); if (wait) { method.waitFor(task); } break; } } } } } } } @Override public void stop(@Nonnull String vmId, boolean force) throws CloudException, InternalException { APITrace.begin(getProvider(), "VM.stop"); try { stopVappOrVm(vmId, force); } finally { APITrace.end(); } } private void stopVappOrVm(@Nonnull String id, boolean force) throws CloudException, InternalException { vCloudMethod method = new vCloudMethod(getProvider()); String xml = method.get("vApp", id); if (xml == null) { throw new CloudException("No information returned for ID: " + id); } Document doc = method.parseXML(xml); String docElementTagName = doc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); NodeList nodes = doc.getElementsByTagName(nsString + "VApp"); if (nodes.getLength() < 1) { nodes = doc.getElementsByTagName(nsString + "Vm"); } else { // 1. It's a vApp ID, nothing to search for, undeploy via vApp if (force) { undeploy(id); } else { undeploy(id, "shutdown"); } return; } // 2. It's a VM. Find vApp ID String vAppId = parseParentVappId(nodes, method); if (vAppId == null) { throw new CloudException("No parent vApp ID found for: " + id); } // 3. Does the vApp contain multiple VMs? // 4a. If the vApp contains multiple VMs, undeploy VM // 4b. If the vApp contains just one VM, undeploy the vApp stopVappOrOneVm(vAppId, id, force); } private void stopVappOrOneVm(String vAppId, String vmId, boolean force) throws CloudException, InternalException { // 3. Does the vApp contain multiple VMs? vCloudMethod method = new vCloudMethod(getProvider()); String xml = method.get("vApp", vAppId); if (xml == null) { throw new CloudException("No information returned for ID: " + vAppId); } Document doc = method.parseXML(xml); String docElementTagName = doc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); NodeList nodes = doc.getElementsByTagName(nsString + "VApp"); NodeList attributes = nodes.item(0).getChildNodes(); int count = 0; for (int i = 0; i < attributes.getLength(); i++) { Node attribute = attributes.item(i); if (attribute.getNodeName().contains(":")) nsString = attribute.getNodeName().substring(0, attribute.getNodeName().indexOf(":") + 1); else nsString = ""; if (attribute.getNodeName().equals(nsString + "Children") && attribute.hasChildNodes()) { NodeList children = attribute.getChildNodes(); for (int j = 0; j < children.getLength(); j++) { Node vmNode = children.item(j); if (vmNode.getNodeName().equalsIgnoreCase(nsString + "Vm") && vmNode.hasAttributes()) { count++; } } } } String powerAction = null; if (!force) { powerAction = "shutdown"; } if (count > 1) { // 4a. If the vApp contains multiple VMs, undeploy VM undeploy(vmId, powerAction); } else if (count == 1) { // 4b. If the vApp contains just one VM, undeploy the vApp undeploy(vAppId, powerAction); } else { throw new CloudException("Expected at least one VM"); } } private void stop(String vAppId, @Nonnull String vmId, boolean force, boolean wait, boolean killByVM) throws CloudException, InternalException { vCloudMethod method = new vCloudMethod(getProvider()); String xml = method.get("vApp", vmId); if (xml != null) { Document doc = method.parseXML(xml); String docElementTagName = doc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); NodeList nodes = doc.getElementsByTagName(nsString + "VApp"); if (nodes.getLength() < 1) { nodes = doc.getElementsByTagName(nsString + "Vm"); } for (int i = 0; i < nodes.getLength(); i++) { NodeList links = nodes.item(i).getChildNodes(); for (int j = 0; j < links.getLength(); j++) { Node node = links.item(j); if (node.getNodeName().contains(":")) nsString = node.getNodeName().substring(0, node.getNodeName().indexOf(":") + 1); else nsString = ""; if (node.getNodeName().equalsIgnoreCase(nsString + "Link") && node.hasAttributes()) { Node rel = node.getAttributes().getNamedItem("rel"); if (force && rel != null && rel.getNodeValue().trim().equalsIgnoreCase("power:powerOff")) { Node href = node.getAttributes().getNamedItem("href"); if (href != null) { String endpoint = href.getNodeValue().trim(); String action = method.getAction(endpoint); String task = method.post(action, endpoint, null, null); if (wait) { method.waitFor(task); } break; } } else if (!force && rel != null && rel.getNodeValue().trim().equalsIgnoreCase("power:shutdown")) { Node href = node.getAttributes().getNamedItem("href"); if (href != null) { String endpoint = href.getNodeValue().trim(); String action = method.getAction(endpoint); String task = method.post(action, endpoint, null, null); if (wait) { method.waitFor(task); } break; } } } } } } } private String parseParentVappId(NodeList nodes, vCloudMethod method) { String nsString = ""; for (int i = 0; i < nodes.getLength(); i++) { NodeList links = nodes.item(i).getChildNodes(); for (int j = 0; j < links.getLength(); j++) { Node node = links.item(j); if (node.getNodeName().contains(":")) nsString = node.getNodeName().substring(0, node.getNodeName().indexOf(":") + 1); else nsString = ""; if (node.getNodeName().equalsIgnoreCase(nsString + "Link") && node.hasAttributes()) { Node rel = node.getAttributes().getNamedItem("rel"); if (rel != null && rel.getNodeValue().trim().equalsIgnoreCase("up")) { Node type = node.getAttributes().getNamedItem("type"); if (type != null && type.getNodeValue().trim().equals(method.getMediaTypeForVApp())) { Node href = node.getAttributes().getNamedItem("href"); if (href != null) { return getProvider().toID(href.getNodeValue().trim()); } } } } } } return null; } @Override public void suspend(@Nonnull String vmId) throws CloudException, InternalException { APITrace.begin(getProvider(), "VM.suspend"); try { suspendVapp(vmId); } finally { APITrace.end(); } } private void suspendVapp(@Nonnull String vappId) throws CloudException, InternalException { vCloudMethod method = new vCloudMethod(getProvider()); String xml = method.get("vApp", vappId); if (xml != null) { Document doc = method.parseXML(xml); String docElementTagName = doc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); NodeList nodes = doc.getElementsByTagName(nsString + "VApp"); if (nodes.getLength() < 1) { nodes = doc.getElementsByTagName(nsString + "Vm"); } for (int i = 0; i < nodes.getLength(); i++) { NodeList links = nodes.item(i).getChildNodes(); for (int j = 0; j < links.getLength(); j++) { Node node = links.item(j); if (node.getNodeName().contains(":")) nsString = node.getNodeName().substring(0, node.getNodeName().indexOf(":") + 1); else nsString = ""; if (node.getNodeName().equalsIgnoreCase(nsString + "Link") && node.hasAttributes()) { Node rel = node.getAttributes().getNamedItem("rel"); if (rel != null && rel.getNodeValue().trim().equalsIgnoreCase("power:suspend")) { Node href = node.getAttributes().getNamedItem("href"); if (href != null) { String endpoint = href.getNodeValue().trim(); String action = method.getAction(endpoint); method.post(action, endpoint, null, null); break; } } } } } } } @Override public void terminate(@Nonnull String vmId, @Nullable String explanation) throws InternalException, CloudException { terminate(vmId); } @Override public void terminate(@Nonnull String vmId) throws InternalException, CloudException { APITrace.begin(getProvider(), "VM.terminate"); try { VirtualMachine vm = getVirtualMachine(vmId); if (vm == null) { throw new CloudException("No such virtual machine: " + vmId); } String vappId = (String) vm.getTag(PARENT_VAPP_ID); Jiterator<VirtualMachine> vms = new Jiterator<VirtualMachine>(); boolean contains = false; int count = 0; loadVmsFor(vm.getProviderDataCenterId(), vappId, vms, getProvider().getNetworkServices().getVlanSupport().listVlans()); for (VirtualMachine v : vms) { count++; if (v.getProviderVirtualMachineId().equals(vmId)) { contains = true; break; } } vCloudMethod method = new vCloudMethod(getProvider()); if (count == 1 && contains) { try { undeploy(vappId); } catch (Throwable t) { logger.error(t.getMessage()); } method.delete("vApp", vappId); } else { try { undeploy(vmId); } catch (Throwable t) { logger.error(t.getMessage()); } method.delete("vApp", vmId); } } finally { APITrace.end(); } } private @Nullable VirtualMachineProduct toProduct(@Nonnull JSONObject json) throws InternalException { VirtualMachineProduct prd = new VirtualMachineProduct(); try { if (json.has("id")) { prd.setProviderProductId(json.getString("id")); } else { return null; } if (json.has("name")) { prd.setName(json.getString("name")); } else { prd.setName(prd.getProviderProductId()); } if (json.has("description")) { prd.setDescription(json.getString("description")); } else { prd.setDescription(prd.getName()); } if (json.has("cpuCount")) { prd.setCpuCount(json.getInt("cpuCount")); } else { prd.setCpuCount(1); } if (json.has("rootVolumeSizeInGb")) { prd.setRootVolumeSize(new Storage<Gigabyte>(json.getInt("rootVolumeSizeInGb"), Storage.GIGABYTE)); } else { prd.setRootVolumeSize(new Storage<Gigabyte>(1, Storage.GIGABYTE)); } if (json.has("ramSizeInMb")) { prd.setRamSize(new Storage<Megabyte>(json.getInt("ramSizeInMb"), Storage.MEGABYTE)); } else { prd.setRamSize(new Storage<Megabyte>(512, Storage.MEGABYTE)); } if (json.has("standardHourlyRates")) { JSONArray rates = json.getJSONArray("standardHourlyRates"); for (int i = 0; i < rates.length(); i++) { JSONObject rate = rates.getJSONObject(i); if (rate.has("rate")) { prd.setStandardHourlyRate((float) rate.getDouble("rate")); } } } } catch (JSONException e) { throw new InternalException(e); } return prd; } private @Nonnull VmState toState(@Nonnull String status) throws CloudException, InternalException { try { int s = Integer.parseInt(status); switch (s) { case 0: case 1: case 5: case 6: case 7: case 9: return VmState.PENDING; case 3: return VmState.SUSPENDED; case 4: return VmState.RUNNING; case 8: return VmState.STOPPED; } logger.warn( "DEBUG: Unknown vCloud status string for " + getContext().getAccountNumber() + ": " + status); return VmState.PENDING; } catch (NumberFormatException e) { logger.error( "DEBUG: Invalid status from vCloud for " + getContext().getAccountNumber() + ": " + status); return VmState.PENDING; } } private @Nullable VirtualMachine toVirtualMachine(@Nonnull String vdcId, @Nonnull String parentVAppId, @Nonnull Node vmNode, @Nonnull Iterable<VLAN> vlans) throws CloudException, InternalException { Node n = vmNode.getAttributes().getNamedItem("href"); VirtualMachine vm = new VirtualMachine(); vm.setProviderMachineImageId("unknown"); vm.setArchitecture(Architecture.I64); vm.setClonable(true); vm.setCreationTimestamp(0L); vm.setCurrentState(VmState.PENDING); vm.setImagable(true); vm.setLastBootTimestamp(0L); vm.setLastPauseTimestamp(0L); vm.setPausable(false); vm.setPersistent(true); vm.setPlatform(Platform.UNKNOWN); vm.setProviderOwnerId(getContext().getAccountNumber()); vm.setRebootable(true); vm.setProviderRegionId(getContext().getRegionId()); vm.setProviderDataCenterId(vdcId); if (n != null) { vm.setProviderVirtualMachineId((getProvider()).toID(n.getNodeValue().trim())); } n = vmNode.getAttributes().getNamedItem("status"); if (n != null) { vm.setCurrentState(toState(n.getNodeValue().trim())); } String vmName = null; String computerName = null; n = vmNode.getAttributes().getNamedItem("name"); if (n != null) { vmName = n.getNodeValue().trim(); } NodeList attributes = vmNode.getChildNodes(); for (int i = 0; i < attributes.getLength(); i++) { Node attribute = attributes.item(i); if (attribute.getNodeName().equalsIgnoreCase("Description") && attribute.hasChildNodes()) { vm.setDescription(attribute.getFirstChild().getNodeValue().trim()); } else if (attribute.getNodeName().equalsIgnoreCase("GuestCustomizationSection") && attribute.hasChildNodes()) { NodeList elements = attribute.getChildNodes(); String adminPassword = null; for (int j = 0; j < elements.getLength(); j++) { Node element = elements.item(j); if (element.getNodeName().equalsIgnoreCase("AdminPassword") && element.hasChildNodes()) { adminPassword = element.getFirstChild().getNodeValue().trim(); } else if (element.getNodeName().equalsIgnoreCase("ComputerName") && element.hasChildNodes()) { computerName = element.getFirstChild().getNodeValue().trim(); } } if (adminPassword != null) { vm.setRootUser(vm.getPlatform().isWindows() ? "administrator" : "root"); vm.setRootPassword(adminPassword); } } else if (attribute.getNodeName().equalsIgnoreCase("DateCreated") && attribute.hasChildNodes()) { vm.setCreationTimestamp((getProvider()).parseTime(attribute.getFirstChild().getNodeValue().trim())); } else if (attribute.getNodeName().equalsIgnoreCase("NetworkConnectionSection") && attribute.hasChildNodes()) { NodeList elements = attribute.getChildNodes(); TreeSet<String> addrs = new TreeSet<String>(); for (int j = 0; j < elements.getLength(); j++) { Node element = elements.item(j); if (element.getNodeName().equalsIgnoreCase("NetworkConnection")) { if (element.hasChildNodes()) { NodeList parts = element.getChildNodes(); Boolean connected = null; String addr = null; for (int k = 0; k < parts.getLength(); k++) { Node part = parts.item(k); if (part.getNodeName().equalsIgnoreCase("IpAddress") && part.hasChildNodes()) { addr = part.getFirstChild().getNodeValue().trim(); } if (part.getNodeName().equalsIgnoreCase("IsConnected") && part.hasChildNodes()) { connected = part.getFirstChild().getNodeValue().trim().equalsIgnoreCase("true"); } } if ((connected == null || connected) && addr != null) { addrs.add(addr); } } if (element.hasAttributes()) { Node net = element.getAttributes().getNamedItem("network"); if (net != null) { String netNameOrId = net.getNodeValue().trim(); boolean compat = (getProvider()).isCompat(); for (VLAN vlan : vlans) { boolean matches = false; if (!compat && vlan.getProviderVlanId().equals(netNameOrId)) { matches = true; } else if (compat && vlan.getProviderVlanId().equals("/network/" + netNameOrId)) { matches = true; } else if (vlan.getName().equals(netNameOrId)) { matches = true; } if (matches) { vm.setProviderVlanId(vlan.getProviderVlanId()); break; } } } } } } if (addrs.size() > 0) { if (addrs.size() == 1) { RawAddress a = new RawAddress(addrs.iterator().next()); if (isPublicIpAddress(a)) { vm.setPublicAddresses(a); } else { vm.setPrivateAddresses(a); } } else { ArrayList<RawAddress> pub = new ArrayList<RawAddress>(); ArrayList<RawAddress> priv = new ArrayList<RawAddress>(); for (String addr : addrs) { RawAddress r = new RawAddress(addr); if (isPublicIpAddress(r)) { pub.add(r); } else { priv.add(r); } } if (priv.size() > 0) { vm.setPrivateAddresses(priv.toArray(new RawAddress[priv.size()])); } if (pub.size() > 0) { vm.setPublicAddresses(pub.toArray(new RawAddress[pub.size()])); } } } } else if (attribute.getNodeName().equalsIgnoreCase("ovf:OperatingSystemSection") && attribute.hasChildNodes()) { NodeList os = attribute.getChildNodes(); for (int j = 0; j < os.getLength(); j++) { Node osdesc = os.item(j); if (osdesc.getNodeName().equalsIgnoreCase("ovf:Description") && osdesc.hasChildNodes()) { String desc = osdesc.getFirstChild().getNodeValue(); vm.setPlatform(Platform.guess(desc)); if (desc.contains("32") || (desc.contains("x86") && !desc.contains("64"))) { vm.setArchitecture(Architecture.I32); } } } } else if (attribute.getNodeName().equalsIgnoreCase("ovf:VirtualHardwareSection") && attribute.hasChildNodes()) { NodeList hardware = attribute.getChildNodes(); int memory = 0, cpu = 0; for (int j = 0; j < hardware.getLength(); j++) { Node item = hardware.item(j); if (item.getNodeName().equalsIgnoreCase("ovf:item") && item.hasChildNodes()) { NodeList bits = item.getChildNodes(); String rt = null; int qty = 0; for (int k = 0; k < bits.getLength(); k++) { Node bit = bits.item(k); if (bit.getNodeName().equalsIgnoreCase("rasd:ResourceType") && bit.hasChildNodes()) { rt = bit.getFirstChild().getNodeValue().trim(); } else if (bit.getNodeName().equalsIgnoreCase("rasd:VirtualQuantity") && bit.hasChildNodes()) { try { qty = Integer.parseInt(bit.getFirstChild().getNodeValue().trim()); } catch (NumberFormatException ignore) { // ignore } } } if (rt != null) { if (rt.equals("3")) { // cpu cpu = qty; } else if (rt.equals("4")) { // memory memory = qty; } /* else if( rt.equals("10") ) { // NIC } else if( rt.equals("17") ) { // disk } */ } } } VirtualMachineProduct product = null; for (VirtualMachineProduct prd : listProducts("bogus", VirtualMachineProductFilterOptions.getInstance().withArchitecture(Architecture.I64))) { if (prd.getCpuCount() == cpu && memory == prd.getRamSize().intValue()) { product = prd; break; } } if (product == null) { vm.setProductId("custom:" + cpu + ":" + memory); } else { vm.setProductId(product.getProviderProductId()); } } } if (vm.getProviderVirtualMachineId() == null) { return null; } if (vmName != null) { vm.setName(vmName); } else if (computerName != null) { vm.setName(computerName); } else { vm.setName(vm.getProviderVirtualMachineId()); } if (vm.getDescription() == null) { vm.setDescription(vm.getName()); } Platform p = vm.getPlatform(); if (p == null || p.equals(Platform.UNKNOWN) || p.equals(Platform.UNIX)) { p = Platform.guess(vm.getName() + " " + vm.getDescription()); if (Platform.UNIX.equals(vm.getPlatform())) { if (p.isUnix()) { vm.setPlatform(p); } } else { vm.setPlatform(p); } } try { vCloudMethod method = new vCloudMethod(getProvider()); String xml = method.get("vApp", vm.getProviderVirtualMachineId() + "/metadata"); if (xml != null && !xml.equals("")) { method.parseMetaData(vm, xml); String t; if (vm.getCreationTimestamp() < 1L) { t = (String) vm.getTag("dsnCreated"); if (t != null) { try { vm.setCreationTimestamp(Long.parseLong(t)); } catch (Throwable parseWarning) { if (logger.isDebugEnabled()) { logger.warn("Failed to parse creation timestamp.", parseWarning); } else { logger.warn("Failed to parse creation timestamp."); } } } } t = (String) vm.getTag("dsnImageId"); logger.debug("dsnImageId = " + t); if (t != null && "unknown".equals(vm.getProviderMachineImageId())) { vm.setProviderMachineImageId(t); logger.debug("Set provider machine image to " + t); } } } catch (Throwable warning) { if (logger.isDebugEnabled()) { logger.warn("Failed to get and parse vm metadata.", warning); } else { logger.warn("Failed to get and parse vm metadata."); } } vm.setTag(PARENT_VAPP_ID, parentVAppId); return vm; } /** * Default undeploy (uses powerOff for UndeployPowerAction) * @param vmId VM or vApp ID * @throws CloudException * @throws InternalException */ public void undeploy(@Nonnull String vmId) throws CloudException, InternalException { undeploy(vmId, null); } /** * Default undeploy, uses supplied string for UndeployPowerAction * @param vmId VM or vApp ID * @param powerAction UndeployPowerAction. If null, use default. * @throws CloudException * @throws InternalException */ public void undeploy(@Nonnull String vmId, String powerAction) throws CloudException, InternalException { vCloudMethod method = new vCloudMethod(getProvider()); String xml = method.get("vApp", vmId); if (xml != null) { Document doc = method.parseXML(xml); String docElementTagName = doc.getDocumentElement().getTagName(); String nsString = ""; if (docElementTagName.contains(":")) nsString = docElementTagName.substring(0, docElementTagName.indexOf(":") + 1); NodeList nodes = doc.getElementsByTagName(nsString + "VApp"); if (nodes.getLength() < 1) { nodes = doc.getElementsByTagName(nsString + "Vm"); } for (int i = 0; i < nodes.getLength(); i++) { NodeList links = nodes.item(i).getChildNodes(); for (int j = 0; j < links.getLength(); j++) { Node node = links.item(j); if (node.getNodeName().contains(":")) nsString = node.getNodeName().substring(0, node.getNodeName().indexOf(":") + 1); else nsString = ""; if (node.getNodeName().equalsIgnoreCase(nsString + "Link") && node.hasAttributes()) { Node rel = node.getAttributes().getNamedItem("rel"); if (rel != null && rel.getNodeValue().trim().equalsIgnoreCase("undeploy")) { Node href = node.getAttributes().getNamedItem("href"); if (href != null) { String endpoint = href.getNodeValue().trim(); String action = method.getAction(endpoint); StringBuilder payload = new StringBuilder(); if (powerAction == null) { payload.append( "<UndeployVAppParams xmlns=\"http://www.vmware.com/vcloud/v1.5\"/>"); } else { payload.append( "<UndeployVAppParams xmlns=\"http://www.vmware.com/vcloud/v1.5\"><UndeployPowerAction>"); payload.append(powerAction); payload.append("</UndeployPowerAction></UndeployVAppParams>"); } try { method.waitFor(method.post(action, endpoint, method.getMediaTypeForActionUndeployVApp(), payload.toString())); } catch (vCloudException e) { if (e.getProviderCode().contains("BUSY_ENTITY")) { try { Thread.sleep(15000L); } catch (InterruptedException ignore) { } undeploy(vmId); return; } throw e; } break; } } } } } } } private @Nonnull String validateHostName(@Nonnull String src) { StringBuilder str = new StringBuilder(); src = src.toLowerCase(); for (int i = 0; i < src.length(); i++) { char c = src.charAt(i); if (str.length() < 1) { if (Character.isLetterOrDigit(c)) { str.append(c); } } else { if (Character.isLetterOrDigit(c)) { str.append(c); } else if (c == '-') { str.append(c); } else if (c == ' ') { str.append('-'); } } } if (str.length() < 1) { str.append("unnamed"); } return str.toString(); } @Override public void setTags(@Nonnull String vmId, @Nonnull Tag... tags) throws CloudException, InternalException { APITrace.begin(getProvider(), "VM.setTags"); try { vCloudMethod method = new vCloudMethod(getProvider()); Tag[] collectionForDelete = TagUtils.getTagsForDelete(getVirtualMachine(vmId).getTags(), tags); if (collectionForDelete.length != 0) { removeTags(vmId, collectionForDelete); } Map<String, Object> metadata = new HashMap<String, Object>(); for (Tag tag : tags) { metadata.put(tag.getKey(), tag.getValue()); } method.postMetaData("vApp", vmId, metadata); } finally { APITrace.end(); } } @Override public void setTags(@Nonnull String[] vmIds, @Nonnull Tag... tags) throws CloudException, InternalException { for (String id : vmIds) { setTags(id, tags); } } @Override public void updateTags(@Nonnull String vmId, @Nonnull Tag... tags) throws CloudException, InternalException { APITrace.begin(getProvider(), "VM.updateTags"); try { vCloudMethod method = new vCloudMethod(getProvider()); Map<String, Object> metadata = new HashMap<String, Object>(); for (Tag tag : tags) { metadata.put(tag.getKey(), tag.getValue()); } method.putMetaData("vApp", vmId, metadata); } finally { APITrace.end(); } } @Override public void updateTags(@Nonnull String[] vmIds, @Nonnull Tag... tags) throws CloudException, InternalException { for (String id : vmIds) { updateTags(id, tags); } } @Override public void removeTags(@Nonnull String vmId, @Nonnull Tag... tags) throws CloudException, InternalException { APITrace.begin(getProvider(), "VM.removeTags"); try { vCloudMethod method = new vCloudMethod(getProvider()); Map<String, Object> metadata = new HashMap<String, Object>(); for (Tag tag : tags) { metadata.put(tag.getKey(), tag.getValue()); } method.delMetaData("vApp", vmId, metadata); } finally { APITrace.end(); } } @Override public void removeTags(@Nonnull String[] vmIds, @Nonnull Tag... tags) throws CloudException, InternalException { for (String id : vmIds) { removeTags(id, tags); } } }