Java tutorial
/** * Copyright (C) 2013-2014 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.azure.compute.vm; import org.apache.commons.codec.binary.Base64; import org.apache.http.client.methods.RequestBuilder; import org.apache.log4j.Logger; import org.dasein.cloud.*; import org.dasein.cloud.azure.Azure; import org.dasein.cloud.azure.AzureConfigException; import org.dasein.cloud.azure.AzureMethod; import org.dasein.cloud.azure.AzureService; import org.dasein.cloud.azure.compute.image.AzureMachineImage; import org.dasein.cloud.azure.compute.vm.model.ConfigurationSetModel; import org.dasein.cloud.azure.compute.vm.model.CreateHostedServiceModel; import org.dasein.cloud.azure.compute.vm.model.DeploymentModel; import org.dasein.cloud.azure.compute.vm.model.Operation; import org.dasein.cloud.azure.model.AzureOperationStatus; import org.dasein.cloud.compute.*; import org.dasein.cloud.dc.DataCenter; import org.dasein.cloud.identity.ServiceAction; import org.dasein.cloud.network.RawAddress; import org.dasein.cloud.network.Subnet; 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.requester.fluent.DaseinRequest; import org.dasein.util.CalendarWrapper; 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.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.annotation.Nonnegative; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.xml.bind.JAXBException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.*; import java.net.URI; import java.net.URISyntaxException; import java.text.SimpleDateFormat; import java.util.*; /** * Implements virtual machine support for Microsoft Azure. * @author George Reese (george.reese@imaginary.com) * @author Qunying Huang * @since 2012.04.1 initial version * @version 2012.04.1 * @version 2012.09 updated for model changes */ public class AzureVM extends AbstractVMSupport<Azure> { static private final Logger logger = Azure.getLogger(AzureVM.class); static public final String DEFAULT_USERNAME = "dasein"; static public final String HOSTED_SERVICES = "/services/hostedservices"; static public final String DEPLOYMENT_RESOURCE = "%s/%s/services/hostedservices/%s/deployments/%s"; static public final String OPERATIONS_RESOURCES = "/services/hostedservices/%s/deployments/%s/roleInstances/%s/Operations"; public AzureVM(Azure provider) { super(provider); } @Override public void start(@Nonnull String vmId) throws InternalException, CloudException { if (vmId == null) throw new InternalException("The id of the Virtual Machine to start cannot be null."); VirtualMachine vm = getVirtualMachine(vmId); if (vm == null) { throw new CloudException("No such virtual machine: " + vmId); } ProviderContext ctx = getProvider().getContext(); if (ctx == null) { throw new AzureConfigException("No context was set for this request"); } String resourceUrl = String.format(OPERATIONS_RESOURCES, vm.getTag("serviceName").toString(), vm.getTag("deploymentName").toString(), vm.getTag("roleName").toString()); AzureMethod azureMethod = new AzureMethod(getProvider()); try { azureMethod.post(resourceUrl, new Operation.StartRoleOperation()); } catch (JAXBException e) { logger.error(e.getMessage()); throw new InternalException(e); } } @Override public VirtualMachine alterVirtualMachineProduct(@Nonnull String virtualMachineId, @Nonnull String productId) throws InternalException, CloudException { if (logger.isTraceEnabled()) { logger.trace("ENTER: " + AzureVM.class.getName() + ".alterVM()"); } if (virtualMachineId == null || productId == null) { throw new AzureConfigException("No virtual machine id and/or product id set for this operation"); } if (!isValidProductId(productId)) throw new InternalException( "Product id invalid: should be one of ExtraSmall, Small, Medium, Large, ExtraLarge"); VirtualMachine vm = getVirtualMachine(virtualMachineId); if (vm == null) { throw new CloudException("No such virtual machine: " + virtualMachineId); } ProviderContext ctx = getProvider().getContext(); if (ctx == null) { throw new AzureConfigException("No context was set for this request"); } String serviceName, deploymentName, roleName; serviceName = vm.getTag("serviceName").toString(); deploymentName = vm.getTag("deploymentName").toString(); roleName = vm.getTag("roleName").toString(); String resourceDir = HOSTED_SERVICES + "/" + serviceName + "/deployments/" + deploymentName + "/roles/" + roleName; try { AzureMethod method = new AzureMethod(getProvider()); Document doc = method.getAsXML(ctx.getAccountNumber(), resourceDir); StringBuilder xml = new StringBuilder(); NodeList roles = doc.getElementsByTagName("PersistentVMRole"); Node role = roles.item(0); NodeList entries = role.getChildNodes(); boolean changeProduct = false; for (int i = 0; i < entries.getLength(); i++) { Node vn = entries.item(i); String vnName = vn.getNodeName(); if (vnName.equalsIgnoreCase("RoleSize") && vn.hasChildNodes()) { if (!productId.equals(vn.getFirstChild().getNodeValue())) { vn.getFirstChild().setNodeValue(productId); changeProduct = true; } else { logger.info("No product change required"); } break; } } String requestId = null; if (changeProduct) { String output = ""; try { TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); StringWriter writer = new StringWriter(); transformer.transform(new DOMSource(doc), new StreamResult(writer)); output = writer.getBuffer().toString().replaceAll("\n|\r", ""); } catch (Exception e) { System.err.println(e); } xml.append(output); logger.debug(xml); logger.debug("___________________________________________________"); resourceDir = HOSTED_SERVICES + "/" + serviceName + "/deployments/" + deploymentName + "/roles/" + roleName; requestId = method.invoke("PUT", ctx.getAccountNumber(), resourceDir, xml.toString()); } else { requestId = "noChange"; } if (requestId != null) { int httpCode = -1; if (!requestId.equals("noChange")) { httpCode = method.getOperationStatus(requestId); while (httpCode == -1) { try { Thread.sleep(15000L); } catch (InterruptedException ignored) { } httpCode = method.getOperationStatus(requestId); } } } return getVirtualMachine(virtualMachineId); } finally { if (logger.isTraceEnabled()) { logger.trace("EXIT: " + AzureVM.class.getName() + ".alterVM()"); } } } private boolean isValidProductId(String productId) throws CloudException, InternalException { Iterable<VirtualMachineProduct> products = listProducts(null, null); for (VirtualMachineProduct p : products) { if (p.getProviderProductId().equals(productId)) { return true; } } return false; } @Override public @Nonnull VirtualMachine clone(@Nonnull String vmId, @Nonnull String intoDcId, @Nonnull String name, @Nonnull String description, boolean powerOn, @Nullable String... firewallIds) throws InternalException, CloudException { throw new OperationNotSupportedException("Not supported in Microsoft Azure"); } @Override public void disableAnalytics(String vmId) throws InternalException, CloudException { // NO-OP } @Override public void enableAnalytics(String vmId) throws InternalException, CloudException { // NO-OP } private transient volatile VMCapabilities capabilities; @Nonnull @Override public VirtualMachineCapabilities getCapabilities() throws InternalException, CloudException { if (capabilities == null) { capabilities = new VMCapabilities(getProvider()); } return capabilities; } @Override public @Nonnull String getConsoleOutput(@Nonnull String vmId) throws InternalException, CloudException { return ""; } @Override public @Nullable VirtualMachineProduct getProduct(@Nonnull String productId) throws InternalException, CloudException { for (VirtualMachineProduct product : listProducts(null, null)) { if (product.getProviderProductId().equals(productId)) { return product; } } return null; } @Override public @Nullable VirtualMachine getVirtualMachine(@Nonnull String vmId) throws InternalException, CloudException { if (vmId == null) throw new InternalException("The id of the Virtual Machine cannot be null."); String[] parts = vmId.split(":"); String sName, deploymentName, roleName; if (parts.length == 3) { sName = parts[0]; deploymentName = parts[1]; roleName = parts[2]; } else if (parts.length == 2) { sName = parts[0]; deploymentName = parts[1]; roleName = sName; } else { sName = vmId; deploymentName = vmId; roleName = vmId; } DataCenter dc = null; AffinityGroup ag = null; ProviderContext ctx = getProvider().getContext(); if (ctx == null) { throw new AzureConfigException("No context was specified for this request"); } AzureMethod method = new AzureMethod(getProvider()); Document doc = method.getAsXML(ctx.getAccountNumber(), HOSTED_SERVICES + "/" + sName + "?embed-detail=true"); if (doc == null) { return null; } NodeList entries = doc.getElementsByTagName("HostedService"); for (int h = 0; h < entries.getLength(); h++) { Node entry = entries.item(h); NodeList attributes = entry.getChildNodes(); boolean mediaLocationFound = false; for (int i = 0; i < attributes.getLength(); i++) { Node attribute = attributes.item(i); if (attribute.getNodeType() == Node.TEXT_NODE) { continue; } if (attribute.getNodeName().equalsIgnoreCase("hostedserviceproperties") && attribute.hasChildNodes()) { NodeList properties = attribute.getChildNodes(); for (int j = 0; j < properties.getLength(); j++) { Node property = properties.item(j); if (property.getNodeType() == Node.TEXT_NODE) { continue; } if (property.getNodeName().equalsIgnoreCase("AffinityGroup") && property.hasChildNodes()) { //get the region for this affinity group String affinityGroup = property.getFirstChild().getNodeValue().trim(); if (affinityGroup != null && !affinityGroup.equals("")) { ag = getProvider().getComputeServices().getAffinityGroupSupport() .get(affinityGroup); if (ag == null) return null; dc = getProvider().getDataCenterServices().getDataCenter(ag.getDataCenterId()); if (dc != null && dc.getRegionId().equals(ctx.getRegionId())) { mediaLocationFound = true; } else { // not correct region/datacenter return null; } } } else if (property.getNodeName().equalsIgnoreCase("location") && property.hasChildNodes()) { if (!mediaLocationFound && !ctx.getRegionId().equals(property.getFirstChild().getNodeValue().trim())) { return null; } } } } } } ArrayList<VirtualMachine> list = new ArrayList<VirtualMachine>(); NodeList deployments = doc.getElementsByTagName("Deployments"); for (int i = 0; i < deployments.getLength(); i++) { Node deployNode = deployments.item(i); NodeList deployAttributes = deployNode.getChildNodes(); String depName = ""; for (int j = 0; j < deployAttributes.getLength(); j++) { Node deployment = deployAttributes.item(j); if (deployment.getNodeType() == Node.TEXT_NODE) { continue; } if (deployment.getNodeName().equalsIgnoreCase("Deployment") && deployment.hasChildNodes()) { NodeList dAttribs = deployment.getChildNodes(); for (int k = 0; k < dAttribs.getLength(); k++) { Node mynode = dAttribs.item(k); if (mynode.getNodeName().equalsIgnoreCase("name") && mynode.hasChildNodes()) { depName = mynode.getFirstChild().getNodeValue().trim(); if (depName.equalsIgnoreCase(deploymentName)) { parseDeployment(ctx, ctx.getRegionId(), sName + ":" + deploymentName, deployment, list); if (list != null && list.size() > 0) { for (VirtualMachine vm : list) { if (vm.getTag("roleName").toString().equalsIgnoreCase(roleName)) { if (dc != null) { vm.setProviderDataCenterId(dc.getProviderDataCenterId()); } else { Collection<DataCenter> dcs = getProvider().getDataCenterServices() .listDataCenters(ctx.getRegionId()); vm.setProviderDataCenterId( dcs.iterator().next().getProviderDataCenterId()); } if (ag != null) { vm.setAffinityGroupId(ag.getAffinityGroupId()); } return vm; } } } } } } } } } return null; } @Override public @Nullable VmStatistics getVMStatistics(String vmId, long from, long to) throws InternalException, CloudException { return new VmStatistics(); } @Override public @Nonnull Iterable<VmStatistics> getVMStatisticsForPeriod(@Nonnull String vmId, @Nonnegative long from, @Nonnegative long to) throws InternalException, CloudException { return Collections.emptyList(); } @Override public boolean isSubscribed() throws CloudException, InternalException { return getProvider().getDataCenterServices().isSubscribed(AzureService.PERSISTENT_VM_ROLE); } @Override public @Nonnull VirtualMachine launch(VMLaunchOptions options) throws CloudException, InternalException { if (logger.isTraceEnabled()) { logger.trace("ENTER: " + AzureVM.class.getName() + ".launch(" + options + ")"); } try { String storageEndpoint = getProvider().getStorageEndpoint(); if (storageEndpoint == null || storageEndpoint.isEmpty()) { getProvider().createDefaultStorageService(); storageEndpoint = getProvider().getStorageEndpoint(); } logger.debug("----------------------------------------------------------"); logger.debug("launching vm " + options.getHostName() + " with machine image id: " + options.getMachineImageId()); AzureMachineImage image = (AzureMachineImage) getProvider().getComputeServices().getImageSupport() .getMachineImage(options.getMachineImageId()); if (image == null) { throw new CloudException("No such image: " + options.getMachineImageId()); } logger.debug("----------------------------------------------------------"); ProviderContext ctx = getProvider().getContext(); if (ctx == null) { throw new AzureConfigException("No context was specified for this request"); } String label; try { label = new String(Base64.encodeBase64(options.getFriendlyName().getBytes("utf-8"))); } catch (UnsupportedEncodingException e) { throw new InternalException(e); } AzureMethod method = new AzureMethod(getProvider()); String hostName = toUniqueId(options.getHostName(), method, ctx); String deploymentSlot = (String) options.getMetaData().get("environment"); String affinityGroupId = options.getAffinityGroupId(); if (deploymentSlot == null) { deploymentSlot = "Production"; } else if (!deploymentSlot.equalsIgnoreCase("Production") && !deploymentSlot.equalsIgnoreCase("Staging")) { deploymentSlot = "Production"; } CreateHostedService(options.getDescription(), ctx.getRegionId(), label, hostName, affinityGroupId); String username; if (image.getPlatform().isWindows()) { username = (options.getBootstrapUser() == null || options.getBootstrapUser().trim().length() == 0 || options.getBootstrapUser().equalsIgnoreCase("root") || options.getBootstrapUser().equalsIgnoreCase("admin") || options.getBootstrapUser().equalsIgnoreCase("administrator") ? "dasein" : options.getBootstrapUser()); } else { username = (options.getBootstrapUser() == null || options.getBootstrapUser().trim().length() == 0 || options.getBootstrapUser().equals("root") ? "dasein" : options.getBootstrapUser()); } String password = (options.getBootstrapPassword() == null ? getProvider().generateToken(8, 15) : options.getBootstrapPassword()); Subnet subnet = null; String vlanName = null; if (options.getVlanId() != null) { subnet = getProvider().getNetworkServices().getVlanSupport().getSubnet(options.getSubnetId()); if (subnet != null) { vlanName = subnet.getTags().get("vlanName"); } else { VLAN vlan = getProvider().getNetworkServices().getVlanSupport().getVlan(options.getVlanId()); if (vlan != null) { vlanName = vlan.getName(); } } } String requestId = null; try { requestId = CreateDeployment(options, storageEndpoint, image, label, hostName, deploymentSlot, subnet, vlanName, username, password); } catch (CloudException e) { logger.error("Launch server failed - now cleaning up service"); DeleteHostedService(hostName); throw e; } long timeout = System.currentTimeMillis() + (CalendarWrapper.MINUTE * 10L); VirtualMachine vm = null; if (requestId != null) { AzureOperationStatus operationStatus = method.get(AzureOperationStatus.class, "/operations/" + requestId); while (operationStatus.getStatus().equalsIgnoreCase("inprogress")) { try { Thread.sleep(15000L); } catch (InterruptedException ignored) { } operationStatus = method.get(AzureOperationStatus.class, "/operations/" + requestId); } vm = getVirtualMachine(hostName + ":" + hostName + ":" + hostName); if (operationStatus.getStatus().equalsIgnoreCase("succeeded")) { //if( vm != null ) { // vm.setRootUser(username); // vm.setRootPassword(password); //} } else if (operationStatus.getStatus().equalsIgnoreCase("failed")) { if (vm != null) { terminate(vm.getProviderVirtualMachineId()); } else { DeleteHostedService(hostName); } String errorMessage = "An error occurred while trying to create deployment for the virtual machine"; errorMessage = errorMessage + String.format("%s reason: %s", operationStatus.getError().getCode(), operationStatus.getError().getMessage()); if (errorMessage.contains("ConflictError") || errorMessage.contains("409")) { throw new CloudException(CloudErrorType.GENERAL, 409, operationStatus.getError().getCode(), errorMessage); } throw new CloudException(errorMessage); } } else { while (timeout > System.currentTimeMillis()) { try { vm = getVirtualMachine(hostName + ":" + hostName + ":" + hostName); } catch (Throwable ignore) { } if (vm != null) { //vm.setRootUser(username); //vm.setRootPassword(password); break; } try { Thread.sleep(15000L); } catch (InterruptedException ignore) { } } } if (vm == null) { throw new CloudException("System timed out waiting for virtual machine to appear"); } if (VmState.STOPPED.equals(vm.getCurrentState())) { start(vm.getProviderVirtualMachineId()); } waitForVMRunning(vm.getProviderVirtualMachineId()); vm = getVirtualMachine(vm.getProviderVirtualMachineId()); vm.setRootUser(username); vm.setRootPassword(password); return vm; } finally { if (logger.isTraceEnabled()) { logger.trace("EXIT: " + AzureVM.class.getName() + ".launch()"); } } } private void DeleteHostedService(String hostName) throws InternalException { String resourceDir = HOSTED_SERVICES + "/" + hostName; long timeout = System.currentTimeMillis() + (CalendarWrapper.MINUTE * 10L); while (timeout > System.currentTimeMillis()) { try { if (logger.isInfoEnabled()) { logger.info("Deleting hosted service " + hostName); } AzureMethod method = new AzureMethod(getProvider()); method.invoke("DELETE", getProvider().getContext().getAccountNumber(), resourceDir, ""); break; } catch (CloudException err) { logger.error("Unable to delete hosted service for " + hostName + ": " + err.getMessage()); logger.error("Retrying..."); try { Thread.sleep(30000L); } catch (InterruptedException ignore) { } continue; } } } private String CreateDeployment(VMLaunchOptions options, String storageEndpoint, AzureMachineImage image, String label, String hostName, String deploymentSlot, Subnet subnet, String vlanName, String username, String password) throws CloudException, InternalException { DeploymentModel deploymentModel = new DeploymentModel(); deploymentModel.setName(hostName); deploymentModel.setDeploymentSlot(deploymentSlot); deploymentModel.setLabel(label); DeploymentModel.RoleModel roleModel = new DeploymentModel.RoleModel(); roleModel.setRoleName(hostName); roleModel.setRoleType("PersistentVMRole"); ArrayList<ConfigurationSetModel> configurations = new ArrayList<ConfigurationSetModel>(); if (image.getPlatform().isWindows()) { ConfigurationSetModel windowsConfigurationSetModel = new ConfigurationSetModel(); windowsConfigurationSetModel.setConfigurationSetType("WindowsProvisioningConfiguration"); windowsConfigurationSetModel.setType("WindowsProvisioningConfigurationSet"); windowsConfigurationSetModel.setComputerName(hostName); windowsConfigurationSetModel.setAdminPassword(password); windowsConfigurationSetModel.setEnableAutomaticUpdates("true"); windowsConfigurationSetModel.setTimeZone("UTC"); windowsConfigurationSetModel.setAdminUsername(username); if (options.getUserData() != null && !options.getUserData().equals("")) windowsConfigurationSetModel .setCustomData(new String(Base64.encodeBase64(options.getUserData().getBytes()))); configurations.add(windowsConfigurationSetModel); } else { ConfigurationSetModel unixConfigurationSetModel = new ConfigurationSetModel(); unixConfigurationSetModel.setConfigurationSetType("LinuxProvisioningConfiguration"); unixConfigurationSetModel.setType("LinuxProvisioningConfigurationSet"); unixConfigurationSetModel.setHostName(hostName); unixConfigurationSetModel.setUserName(username); unixConfigurationSetModel.setUserPassword(password); unixConfigurationSetModel.setDisableSshPasswordAuthentication("false"); if (options.getUserData() != null && !options.getUserData().equals("")) unixConfigurationSetModel .setCustomData(new String(Base64.encodeBase64(options.getUserData().getBytes()))); configurations.add(unixConfigurationSetModel); } ConfigurationSetModel networkConfigurationSetModel = new ConfigurationSetModel(); networkConfigurationSetModel.setConfigurationSetType("NetworkConfiguration"); ArrayList<ConfigurationSetModel.InputEndpointModel> inputEndpointModels = new ArrayList<ConfigurationSetModel.InputEndpointModel>(); if (image.getPlatform().isWindows()) { ConfigurationSetModel.InputEndpointModel inputEndpointModel = new ConfigurationSetModel.InputEndpointModel(); inputEndpointModel.setLocalPort("3389"); inputEndpointModel.setName("RemoteDesktop"); inputEndpointModel.setPort("58622"); inputEndpointModel.setProtocol("TCP"); inputEndpointModels.add(inputEndpointModel); } else { ConfigurationSetModel.InputEndpointModel inputEndpointModel = new ConfigurationSetModel.InputEndpointModel(); inputEndpointModel.setLocalPort("22"); inputEndpointModel.setName("SSH"); inputEndpointModel.setPort("22"); inputEndpointModel.setProtocol("TCP"); inputEndpointModels.add(inputEndpointModel); } networkConfigurationSetModel.setInputEndpoints(inputEndpointModels); if (subnet != null) { ArrayList<String> subnets = new ArrayList<String>(); subnets.add(subnet.getName()); networkConfigurationSetModel.setSubnetNames(subnets); } configurations.add(networkConfigurationSetModel); roleModel.setConfigurationsSets(configurations); if (image.getAzureImageType().equalsIgnoreCase("osimage")) { DeploymentModel.OSVirtualHardDiskModel osVirtualHardDiskModel = new DeploymentModel.OSVirtualHardDiskModel(); osVirtualHardDiskModel.setHostCaching("ReadWrite"); osVirtualHardDiskModel.setDiskLabel("OS"); String vhdFileName = String.format("%s-%s-%s-%s.vhd", hostName, hostName, hostName, new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())); osVirtualHardDiskModel.setMediaLink(storageEndpoint + "vhds/" + vhdFileName); osVirtualHardDiskModel.setSourceImageName(options.getMachineImageId()); roleModel.setOsVirtualDisk(osVirtualHardDiskModel); } else if (image.getAzureImageType().equalsIgnoreCase("vmimage")) { roleModel.setVmImageName(image.getProviderMachineImageId()); } roleModel.setRoleSize(options.getStandardProductId()); ArrayList<DeploymentModel.RoleModel> roles = new ArrayList<DeploymentModel.RoleModel>(); roles.add(roleModel); deploymentModel.setRoles(roles); if (options.getVlanId() != null) { deploymentModel.setVirtualNetworkName(vlanName); } try { AzureMethod method = new AzureMethod(getProvider()); return method.post(HOSTED_SERVICES + "/" + hostName + "/deployments", deploymentModel); } catch (JAXBException e) { logger.error(e.getMessage()); throw new CloudException(e); } } private void CreateHostedService(String description, String regionId, String label, String hostName, String affinityGroupId) throws CloudException, InternalException { CreateHostedServiceModel createHostedServiceModel = new CreateHostedServiceModel(); createHostedServiceModel.setServiceName(hostName); createHostedServiceModel.setLabel(label); createHostedServiceModel.setDescription(description); if (affinityGroupId != null) { createHostedServiceModel.setAffinityGroup(affinityGroupId); } else { createHostedServiceModel.setLocation(regionId); } try { AzureMethod method = new AzureMethod(getProvider()); String requestId = method.post(HOSTED_SERVICES, createHostedServiceModel); if (requestId != null) { AzureOperationStatus operationStatus = method.get(AzureOperationStatus.class, "/operations/" + requestId); while (operationStatus.getStatus().equalsIgnoreCase("inprogress")) { try { Thread.sleep(15000L); } catch (InterruptedException ignored) { } operationStatus = method.get(AzureOperationStatus.class, "/operations/" + requestId); } if (operationStatus.getStatus().equalsIgnoreCase("failed")) { String errorMessage = "An error occurred while trying to launch the virtual machine. Create hosted service failed."; if (operationStatus.getError() != null) { errorMessage = errorMessage + String.format("%s reason: %s", operationStatus.getError().getCode(), operationStatus.getError().getMessage()); if (errorMessage.contains("ConflictError") || errorMessage.contains("409")) { throw new CloudException(CloudErrorType.GENERAL, 409, operationStatus.getError().getCode(), errorMessage); } } throw new CloudException(errorMessage); } } } catch (JAXBException e) { logger.error(e.getMessage()); throw new CloudException(e); } } @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()); } @Override public @Nonnull Iterable<VirtualMachineProduct> listProducts(@Nonnull String machineImageId, @Nonnull VirtualMachineProductFilterOptions options) throws InternalException, CloudException { APITrace.begin(getProvider(), "listVMProducts"); try { Cache<VirtualMachineProduct> cache = Cache.getInstance(getProvider(), "products" + machineImageId, VirtualMachineProduct.class, CacheLevel.REGION, new TimePeriod<Day>(1, TimePeriod.DAY)); Iterable<VirtualMachineProduct> products = cache.get(getContext()); if (products == null) { List<VirtualMachineProduct> list = new ArrayList<VirtualMachineProduct>(); try { String resource = ((Azure) getProvider()).getVMProductsResource(); InputStream input = AzureVM.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 || (getProvider().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 = 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(); } } @Nonnull @Override public Iterable<ResourceStatus> listVirtualMachineStatus() throws InternalException, CloudException { ProviderContext ctx = getProvider().getContext(); if (ctx == null) { throw new AzureConfigException("No context was specified for this request"); } AzureMethod method = new AzureMethod(getProvider()); Document doc = method.getAsXML(ctx.getAccountNumber(), HOSTED_SERVICES); if (doc == null) { return Collections.emptyList(); } NodeList entries = doc.getElementsByTagName("HostedService"); ArrayList<ResourceStatus> status = new ArrayList<ResourceStatus>(); for (int i = 0; i < entries.getLength(); i++) { parseHostedServiceForStatus(ctx, entries.item(i), null, status); } return status; } @Override public @Nonnull Iterable<VirtualMachine> listVirtualMachines() throws InternalException, CloudException { ProviderContext ctx = getProvider().getContext(); if (ctx == null) { throw new AzureConfigException("No context was specified for this request"); } AzureMethod method = new AzureMethod(getProvider()); Document doc = method.getAsXML(ctx.getAccountNumber(), HOSTED_SERVICES); if (doc == null) { return Collections.emptyList(); } NodeList entries = doc.getElementsByTagName("HostedService"); ArrayList<VirtualMachine> vms = new ArrayList<VirtualMachine>(); for (int i = 0; i < entries.getLength(); i++) { parseHostedService(ctx, entries.item(i), null, vms); } return vms; } @Nonnull @Override public Iterable<VirtualMachine> listVirtualMachines(@Nullable VMFilterOptions vmFilterOptions) throws InternalException, CloudException { Iterable<VirtualMachine> vms = listVirtualMachines(); ArrayList<VirtualMachine> list = new ArrayList<VirtualMachine>(); for (VirtualMachine vm : vms) { if (vm.getName().matches(vmFilterOptions.getRegex())) { list.add(vm); } } return list; } private void parseDeployment(@Nonnull ProviderContext ctx, @Nonnull String regionId, @Nonnull String serviceName, @Nonnull Node node, @Nonnull List<VirtualMachine> virtualMachines) { ArrayList<VirtualMachine> list = new ArrayList<VirtualMachine>(); NodeList attributes = node.getChildNodes(); String deploymentSlot = null; String deploymentId = null; String dnsName = null; String vmRoleName = null; String imageId = null; String vmImageId = null; String diskOS = null; String mediaLink = null; String vlan = null; String subnetName = null; boolean isLocked = false; for (int i = 0; i < attributes.getLength(); i++) { Node attribute = attributes.item(i); if (attribute.getNodeType() == Node.TEXT_NODE) { continue; } if (attribute.getNodeName().equalsIgnoreCase("deploymentslot") && attribute.hasChildNodes()) { deploymentSlot = attribute.getFirstChild().getNodeValue().trim(); } else if (attribute.getNodeName().equalsIgnoreCase("privateid") && attribute.hasChildNodes()) { deploymentId = attribute.getFirstChild().getNodeValue().trim(); } else if (attribute.getNodeName().equalsIgnoreCase("locked") && attribute.hasChildNodes()) { if (attribute.getFirstChild().getNodeValue().trim().equalsIgnoreCase("true")) { isLocked = true; } } else if (attribute.getNodeName().equalsIgnoreCase("url") && attribute.hasChildNodes()) { try { URI u = new URI(attribute.getFirstChild().getNodeValue().trim()); dnsName = u.getHost(); } catch (URISyntaxException e) { // ignore } } else if (attribute.getNodeName().equalsIgnoreCase("roleinstancelist") && attribute.hasChildNodes()) { NodeList roleInstances = attribute.getChildNodes(); for (int j = 0; j < roleInstances.getLength(); j++) { Node roleInstance = roleInstances.item(j); if (roleInstance.getNodeType() == Node.TEXT_NODE) { continue; } if (roleInstance.getNodeName().equalsIgnoreCase("roleinstance") && roleInstance.hasChildNodes()) { VirtualMachine role = new VirtualMachine(); role.setArchitecture(Architecture.I64); role.setClonable(false); role.setCurrentState(VmState.TERMINATED); role.setImagable(false); role.setPersistent(true); role.setPlatform(Platform.UNKNOWN); role.setProviderOwnerId(ctx.getAccountNumber()); role.setProviderRegionId(regionId); role.setProviderDataCenterId(regionId); NodeList roleAttributes = roleInstance.getChildNodes(); for (int l = 0; l < roleAttributes.getLength(); l++) { Node roleAttribute = roleAttributes.item(l); if (roleAttribute.getNodeType() == Node.TEXT_NODE) { continue; } if (roleAttribute.getNodeName().equalsIgnoreCase("RoleName") && roleAttribute.hasChildNodes()) { String vmId = roleAttribute.getFirstChild().getNodeValue().trim(); role.setProviderVirtualMachineId(serviceName + ":" + vmId); role.setName(vmId); } else if (roleAttribute.getNodeName().equalsIgnoreCase("instancesize") && roleAttribute.hasChildNodes()) { role.setProductId(roleAttribute.getFirstChild().getNodeValue().trim()); } else if (roleAttribute.getNodeName().equalsIgnoreCase("instanceupgradedomain") && roleAttribute.hasChildNodes()) { role.setTag("UpgradeDomain", roleAttribute.getFirstChild().getNodeValue().trim()); } else if (roleAttribute.getNodeName().equalsIgnoreCase("instanceerrorcode") && roleAttribute.hasChildNodes()) { role.setTag("ErrorCode", roleAttribute.getFirstChild().getNodeValue().trim()); } else if (roleAttribute.getNodeName().equalsIgnoreCase("instancefaultdomain") && roleAttribute.hasChildNodes()) { role.setTag("FaultDomain", roleAttribute.getFirstChild().getNodeValue().trim()); } else if (roleAttribute.getNodeName().equalsIgnoreCase("fqdn") && roleAttribute.hasChildNodes()) { role.setPrivateDnsAddress(roleAttribute.getFirstChild().getNodeValue().trim()); } else if (roleAttribute.getNodeName().equalsIgnoreCase("ipaddress") && roleAttribute.hasChildNodes()) { role.setPrivateAddresses(new RawAddress[] { new RawAddress(roleAttribute.getFirstChild().getNodeValue().trim()) }); } else if (roleAttribute.getNodeName().equalsIgnoreCase("instanceendpoints") && roleAttribute.hasChildNodes()) { NodeList endpoints = roleAttribute.getChildNodes(); for (int m = 0; m < endpoints.getLength(); m++) { Node endpoint = endpoints.item(m); if (endpoint.hasChildNodes()) { NodeList ea = endpoint.getChildNodes(); for (int n = 0; n < ea.getLength(); n++) { Node a = ea.item(n); if (a.getNodeName().equalsIgnoreCase("vip") && a.hasChildNodes()) { String addr = a.getFirstChild().getNodeValue().trim(); RawAddress[] ips = role.getPublicAddresses(); if (ips == null || ips.length < 1) { role.setPublicAddresses( new RawAddress[] { new RawAddress(addr) }); } else { boolean found = false; for (RawAddress ip : ips) { if (ip.getIpAddress().equals(addr)) { found = true; break; } } if (!found) { RawAddress[] tmp = new RawAddress[ips.length + 1]; System.arraycopy(ips, 0, tmp, 0, ips.length); tmp[tmp.length - 1] = new RawAddress(addr); role.setPublicAddresses(tmp); } } } } } } } else if (roleAttribute.getNodeName().equalsIgnoreCase("PowerState") && roleAttribute.hasChildNodes()) { String powerStatus = roleAttribute.getFirstChild().getNodeValue().trim(); if ("Started".equalsIgnoreCase(powerStatus)) { role.setCurrentState(VmState.RUNNING); } else if ("Stopped".equalsIgnoreCase(powerStatus)) { role.setCurrentState(VmState.STOPPED); role.setImagable(true); } else if ("Stopping".equalsIgnoreCase(powerStatus)) { role.setCurrentState(VmState.STOPPING); } else if ("Starting".equalsIgnoreCase(powerStatus)) { role.setCurrentState(VmState.PENDING); } else { logger.warn("DEBUG: Unknown Azure status: " + powerStatus); } } } if (role.getProviderVirtualMachineId() == null) { continue; } if (role.getName() == null) { role.setName(role.getProviderVirtualMachineId()); } if (role.getDescription() == null) { role.setDescription(role.getName()); } if (role.getPlatform().equals(Platform.UNKNOWN)) { String descriptor = (role.getProviderVirtualMachineId() + " " + role.getName() + " " + role.getDescription() + " " + role.getProviderMachineImageId()) .replaceAll("_", " "); role.setPlatform(Platform.guess(descriptor)); } else if (role.getPlatform().equals(Platform.UNIX)) { String descriptor = (role.getProviderVirtualMachineId() + " " + role.getName() + " " + role.getDescription() + " " + role.getProviderMachineImageId()) .replaceAll("_", " "); Platform p = Platform.guess(descriptor); if (p.isUnix()) { role.setPlatform(p); } } list.add(role); } } } //Contain the information about disk and firewall; else if (attribute.getNodeName().equalsIgnoreCase("rolelist") && attribute.hasChildNodes()) { NodeList roles = attribute.getChildNodes(); for (int k = 0; k < roles.getLength(); k++) { Node role = roles.item(k); if (role.getNodeName().equalsIgnoreCase("role") && role.hasChildNodes()) { if (role.hasAttributes()) { Node n = role.getAttributes().getNamedItem("i:type"); if (n != null) { String val = n.getNodeValue(); if (!"PersistentVMRole".equalsIgnoreCase(val)) { continue; } } } NodeList roleAttributes = role.getChildNodes(); for (int l = 0; l < roleAttributes.getLength(); l++) { Node roleAttribute = roleAttributes.item(l); if (roleAttribute.getNodeType() == Node.TEXT_NODE) { continue; } if (roleAttribute.getNodeName().equalsIgnoreCase("osvirtualharddisk") && roleAttribute.hasChildNodes()) { NodeList diskAttributes = roleAttribute.getChildNodes(); for (int m = 0; m < diskAttributes.getLength(); m++) { Node diskAttribute = diskAttributes.item(m); if (diskAttribute.getNodeName().equalsIgnoreCase("SourceImageName") && diskAttribute.hasChildNodes()) { imageId = diskAttribute.getFirstChild().getNodeValue().trim(); } else if (diskAttribute.getNodeName().equalsIgnoreCase("medialink") && diskAttribute.hasChildNodes()) { mediaLink = diskAttribute.getFirstChild().getNodeValue().trim(); } else if (diskAttribute.getNodeName().equalsIgnoreCase("OS") && diskAttribute.hasChildNodes()) { diskOS = diskAttribute.getFirstChild().getNodeValue().trim(); } } } else if (roleAttribute.getNodeName().equalsIgnoreCase("RoleName") && roleAttribute.hasChildNodes()) { vmRoleName = roleAttribute.getFirstChild().getNodeValue().trim(); } else if (roleAttribute.getNodeName().equalsIgnoreCase("VMImageName") && roleAttribute.hasChildNodes()) { vmImageId = roleAttribute.getFirstChild().getNodeValue().trim(); } else if (roleAttribute.getNodeName().equalsIgnoreCase("ConfigurationSets") && roleAttribute.hasChildNodes()) { NodeList configs = ((Element) roleAttribute) .getElementsByTagName("ConfigurationSet"); for (int n = 0; n < configs.getLength(); n++) { boolean foundNetConfig = false; Node config = configs.item(n); if (config.hasAttributes()) { Node c = config.getAttributes().getNamedItem("i:type"); if (c != null) { String val = c.getNodeValue(); if (!"NetworkConfigurationSet".equalsIgnoreCase(val)) { continue; } } } if (config.hasChildNodes()) { NodeList configAttribs = config.getChildNodes(); for (int o = 0; o < configAttribs.getLength(); o++) { Node attrib = configAttribs.item(o); if (attrib.getNodeName().equalsIgnoreCase("SubnetNames") && attrib.hasChildNodes()) { NodeList subnets = attrib.getChildNodes(); for (int p = 0; p < subnets.getLength(); p++) { Node subnet = subnets.item(p); if (subnet.getNodeName().equalsIgnoreCase("SubnetName") && subnet.hasChildNodes()) { subnetName = subnet.getFirstChild().getNodeValue().trim(); } } } } } } } } } } } else if (attribute.getNodeName().equalsIgnoreCase("virtualnetworkname") && attribute.hasChildNodes()) { vlan = attribute.getFirstChild().getNodeValue().trim(); } } if (vmRoleName != null) { for (VirtualMachine vm : list) { if (deploymentSlot != null) { vm.setTag("environment", deploymentSlot); } if (deploymentId != null) { vm.setTag("deploymentId", deploymentId); } if (dnsName != null) { vm.setPublicDnsAddress(dnsName); } if (vmImageId != null) { vm.setProviderMachineImageId(vmImageId); vm.setPlatform(Platform.guess(diskOS)); } else if (imageId != null) { Platform fallback = vm.getPlatform(); vm.setProviderMachineImageId(imageId); vm.setPlatform(Platform.guess(vm.getProviderMachineImageId())); if (vm.getPlatform().equals(Platform.UNKNOWN)) { try { MachineImage img = getProvider().getComputeServices().getImageSupport() .getMachineImage(vm.getProviderMachineImageId()); if (img != null) { vm.setPlatform(img.getPlatform()); } } catch (Throwable t) { logger.warn("Error loading machine image: " + t.getMessage()); } if (vm.getPlatform().equals(Platform.UNKNOWN)) { vm.setPlatform(fallback); } } } if (vlan != null) { String providerVlanId = null; try { providerVlanId = getProvider().getNetworkServices().getVlanSupport().getVlan(vlan) .getProviderVlanId(); vm.setProviderVlanId(providerVlanId); } catch (CloudException e) { logger.error("Error getting vlan id for vlan " + vlan); continue; } catch (InternalException ie) { logger.error("Error getting vlan id for vlan " + vlan); continue; } if (subnetName != null) { vm.setProviderSubnetId(subnetName + "_" + providerVlanId); } } String[] parts = vm.getProviderVirtualMachineId().split(":"); String sName, deploymentName, roleName; if (parts.length == 3) { sName = parts[0]; deploymentName = parts[1]; roleName = parts[2]; } else if (parts.length == 2) { sName = parts[0]; deploymentName = parts[1]; roleName = deploymentName; } else { sName = serviceName; deploymentName = serviceName; roleName = serviceName; } vm.setTag("serviceName", sName); vm.setTag("deploymentName", deploymentName); vm.setTag("roleName", roleName); if (isLocked) { vm.setTag("locked", String.valueOf(isLocked)); } if (mediaLink != null) { vm.setTag("mediaLink", mediaLink); } virtualMachines.add(vm); } } } private void parseStatus(@Nonnull ProviderContext ctx, @Nonnull String regionId, @Nonnull String serviceName, @Nonnull Node node, @Nonnull List<ResourceStatus> status) { ArrayList<ResourceStatus> list = new ArrayList<ResourceStatus>(); NodeList attributes = node.getChildNodes(); String id = ""; ResourceStatus s = null; for (int i = 0; i < attributes.getLength(); i++) { Node attribute = attributes.item(i); if (attribute.getNodeType() == Node.TEXT_NODE) { continue; } if (attribute.getNodeName().equalsIgnoreCase("roleinstancelist") && attribute.hasChildNodes()) { NodeList roleInstances = attribute.getChildNodes(); for (int j = 0; j < roleInstances.getLength(); j++) { Node roleInstance = roleInstances.item(j); if (roleInstance.getNodeType() == Node.TEXT_NODE) { continue; } if (roleInstance.getNodeName().equalsIgnoreCase("roleinstance") && roleInstance.hasChildNodes()) { NodeList roleAttributes = roleInstance.getChildNodes(); for (int l = 0; l < roleAttributes.getLength(); l++) { Node roleAttribute = roleAttributes.item(l); if (roleAttribute.getNodeType() == Node.TEXT_NODE) { continue; } if (roleAttribute.getNodeName().equalsIgnoreCase("RoleName") && roleAttribute.hasChildNodes()) { String vmId = roleAttribute.getFirstChild().getNodeValue().trim(); id = serviceName + ":" + vmId; } else if (roleAttribute.getNodeName().equalsIgnoreCase("PowerState") && roleAttribute.hasChildNodes()) { String powerStatus = roleAttribute.getFirstChild().getNodeValue().trim(); if ("Started".equalsIgnoreCase(powerStatus)) { s = new ResourceStatus(id, VmState.RUNNING); } else if ("Stopped".equalsIgnoreCase(powerStatus)) { s = new ResourceStatus(id, VmState.STOPPED); } else if ("Stopping".equalsIgnoreCase(powerStatus)) { s = new ResourceStatus(id, VmState.STOPPING); } else if ("Starting".equalsIgnoreCase(powerStatus)) { s = new ResourceStatus(id, VmState.PENDING); } else { logger.warn("DEBUG: Unknown Azure status: " + powerStatus); } } } if (id == null) { continue; } if (s != null) { list.add(s); s = null; } } } } } for (ResourceStatus rs : list) { status.add(rs); } } private void parseHostedService(@Nonnull ProviderContext ctx, @Nonnull Node entry, @Nullable String serviceName, @Nonnull List<VirtualMachine> virtualMachines) throws CloudException, InternalException { String regionId = ctx.getRegionId(); if (regionId == null) { throw new AzureConfigException("No region ID was specified for this request"); } NodeList attributes = entry.getChildNodes(); String uri = null; long created = 0L; String service = null; boolean mediaLocationFound = false; DataCenter dc = null; AffinityGroup affinityGroupModel = null; for (int i = 0; i < attributes.getLength(); i++) { Node attribute = attributes.item(i); if (attribute.getNodeType() == Node.TEXT_NODE) { continue; } if (attribute.getNodeName().equalsIgnoreCase("url") && attribute.hasChildNodes()) { uri = attribute.getFirstChild().getNodeValue().trim(); } else if (attribute.getNodeName().equalsIgnoreCase("servicename") && attribute.hasChildNodes()) { service = attribute.getFirstChild().getNodeValue().trim(); if (serviceName != null && !service.equals(serviceName)) { return; } } else if (attribute.getNodeName().equalsIgnoreCase("hostedserviceproperties") && attribute.hasChildNodes()) { NodeList properties = attribute.getChildNodes(); for (int j = 0; j < properties.getLength(); j++) { Node property = properties.item(j); if (property.getNodeType() == Node.TEXT_NODE) { continue; } if (property.getNodeName().equalsIgnoreCase("AffinityGroup") && property.hasChildNodes()) { //get the region for this affinity group String affinityGroup = property.getFirstChild().getNodeValue().trim(); if (affinityGroup != null && !affinityGroup.equals("")) { affinityGroupModel = getProvider().getComputeServices().getAffinityGroupSupport() .get(affinityGroup); if (affinityGroupModel == null) return; dc = getProvider().getDataCenterServices() .getDataCenter(affinityGroupModel.getDataCenterId()); if (dc != null && dc.getRegionId().equals(regionId)) { mediaLocationFound = true; } else { // not correct region/datacenter return; } } } else if (property.getNodeName().equalsIgnoreCase("location") && property.hasChildNodes()) { if (!mediaLocationFound && !regionId.equals(property.getFirstChild().getNodeValue().trim())) { return; } } else if (property.getNodeName().equalsIgnoreCase("datecreated") && property.hasChildNodes()) { created = getProvider().parseTimestamp(property.getFirstChild().getNodeValue().trim()); } } } } if (uri == null || service == null) { return; } AzureMethod method = new AzureMethod(getProvider()); //dmayne 20130416: get the deployment names for each hosted service so we can then extract the detail String deployURL = HOSTED_SERVICES + "/" + service + "?embed-detail=true"; Document deployDoc = method.getAsXML(ctx.getAccountNumber(), deployURL); if (deployDoc == null) { return; } NodeList deployments = deployDoc.getElementsByTagName("Deployments"); for (int i = 0; i < deployments.getLength(); i++) { Node deployNode = deployments.item(i); NodeList deployAttributes = deployNode.getChildNodes(); String deploymentName = ""; for (int j = 0; j < deployAttributes.getLength(); j++) { Node deployment = deployAttributes.item(j); if (deployment.getNodeType() == Node.TEXT_NODE) { continue; } if (deployment.getNodeName().equalsIgnoreCase("Deployment") && deployment.hasChildNodes()) { NodeList dAttribs = deployment.getChildNodes(); for (int k = 0; k < dAttribs.getLength(); k++) { Node mynode = dAttribs.item(k); if (mynode.getNodeName().equalsIgnoreCase("name") && mynode.hasChildNodes()) { deploymentName = mynode.getFirstChild().getNodeValue().trim(); parseDeployment(ctx, regionId, service + ":" + deploymentName, deployment, virtualMachines); for (VirtualMachine vm : virtualMachines) { if (vm.getCreationTimestamp() < 1L) { vm.setCreationTimestamp(created); } if (dc != null) { vm.setProviderDataCenterId(dc.getProviderDataCenterId()); } else { Collection<DataCenter> dcs = getProvider().getDataCenterServices() .listDataCenters(regionId); vm.setProviderDataCenterId(dcs.iterator().next().getProviderDataCenterId()); } if (affinityGroupModel != null) { vm.setAffinityGroupId(affinityGroupModel.getAffinityGroupId()); } } } } } } } } private void parseHostedServiceForStatus(@Nonnull ProviderContext ctx, @Nonnull Node entry, @Nullable String serviceName, @Nonnull List<ResourceStatus> status) throws CloudException, InternalException { String regionId = ctx.getRegionId(); if (regionId == null) { throw new AzureConfigException("No region ID was specified for this request"); } NodeList attributes = entry.getChildNodes(); String uri = null; String service = null; for (int i = 0; i < attributes.getLength(); i++) { Node attribute = attributes.item(i); if (attribute.getNodeType() == Node.TEXT_NODE) { continue; } if (attribute.getNodeName().equalsIgnoreCase("url") && attribute.hasChildNodes()) { uri = attribute.getFirstChild().getNodeValue().trim(); } else if (attribute.getNodeName().equalsIgnoreCase("servicename") && attribute.hasChildNodes()) { service = attribute.getFirstChild().getNodeValue().trim(); if (serviceName != null && !service.equals(serviceName)) { return; } } else if (attribute.getNodeName().equalsIgnoreCase("hostedserviceproperties") && attribute.hasChildNodes()) { NodeList properties = attribute.getChildNodes(); boolean mediaLocationFound = false; for (int j = 0; j < properties.getLength(); j++) { Node property = properties.item(j); if (property.getNodeType() == Node.TEXT_NODE) { continue; } if (property.getNodeName().equalsIgnoreCase("AffinityGroup") && property.hasChildNodes()) { //get the region for this affinity group String affinityGroup = property.getFirstChild().getNodeValue().trim(); if (affinityGroup != null && !affinityGroup.equals("")) { AffinityGroup affinityGroupModel = getProvider().getComputeServices() .getAffinityGroupSupport().get(affinityGroup); if (affinityGroupModel == null) return; DataCenter dc = getProvider().getDataCenterServices() .getDataCenter(affinityGroupModel.getDataCenterId()); if (dc != null && dc.getRegionId().equals(regionId)) { mediaLocationFound = true; } else { // not correct region/datacenter return; } } } else if (property.getNodeName().equalsIgnoreCase("location") && property.hasChildNodes()) { if (!mediaLocationFound && !regionId.equals(property.getFirstChild().getNodeValue().trim())) { return; } } } } } if (uri == null || service == null) { return; } AzureMethod method = new AzureMethod(getProvider()); //dmayne 20130416: get the deployment names for each hosted service so we can then extract the detail String deployURL = HOSTED_SERVICES + "/" + service + "?embed-detail=true"; Document deployDoc = method.getAsXML(ctx.getAccountNumber(), deployURL); if (deployDoc == null) { return; } NodeList deployments = deployDoc.getElementsByTagName("Deployments"); for (int i = 0; i < deployments.getLength(); i++) { Node deployNode = deployments.item(i); NodeList deployAttributes = deployNode.getChildNodes(); String deploymentName = ""; for (int j = 0; j < deployAttributes.getLength(); j++) { Node deployment = deployAttributes.item(j); if (deployment.getNodeType() == Node.TEXT_NODE) { continue; } if (deployment.getNodeName().equalsIgnoreCase("Deployment") && deployment.hasChildNodes()) { NodeList dAttribs = deployment.getChildNodes(); for (int k = 0; k < dAttribs.getLength(); k++) { Node mynode = dAttribs.item(k); if (mynode.getNodeName().equalsIgnoreCase("name") && mynode.hasChildNodes()) { deploymentName = mynode.getFirstChild().getNodeValue().trim(); parseStatus(ctx, regionId, service + ":" + deploymentName, deployment, status); } } } } } } @Override public void reboot(@Nonnull String vmId) throws CloudException, InternalException { if (vmId == null) throw new InternalException("The id of the Virtual Machine to reboot cannot be null."); ProviderContext ctx = getProvider().getContext(); if (ctx == null) { throw new AzureConfigException("No context was set for this request"); } VirtualMachine vm = getVirtualMachine(vmId); if (vm == null) { throw new CloudException("No such virtual machine: " + vmId); } String resourceUrl = String.format(OPERATIONS_RESOURCES, vm.getTag("serviceName").toString(), vm.getTag("deploymentName").toString(), vm.getTag("roleName").toString()); AzureMethod azureMethod = new AzureMethod(getProvider()); try { azureMethod.post(resourceUrl, new Operation.RestartRoleOperation()); } catch (JAXBException e) { logger.error(e.getMessage()); throw new InternalException(e); } } @Override public void resume(@Nonnull String vmId) throws CloudException, InternalException { this.start(vmId); } @Override public void pause(@Nonnull String vmId) throws InternalException, CloudException { throw new OperationNotSupportedException("Pause/unpause is not supported in Microsoft Azure"); } @Override public void stop(@Nonnull String vmId, boolean force) throws InternalException, CloudException { if (vmId == null) throw new InternalException("The id of the Virtual Machine to stop cannot be null."); ProviderContext ctx = getProvider().getContext(); if (ctx == null) { throw new AzureConfigException("No context was set for this request"); } VirtualMachine vm = getVirtualMachine(vmId); if (vm == null) { throw new CloudException("No such virtual machine: " + vmId); } String resourceUrl = String.format(OPERATIONS_RESOURCES, vm.getTag("serviceName").toString(), vm.getTag("deploymentName").toString(), vm.getTag("roleName").toString()); AzureMethod azureMethod = new AzureMethod(getProvider()); Operation.ShutdownRoleOperation shutdownRoleOperation = new Operation.ShutdownRoleOperation(); shutdownRoleOperation.setPostShutdownAction("Stopped"); try { azureMethod.post(resourceUrl, shutdownRoleOperation); } catch (JAXBException e) { logger.error(e.getMessage()); throw new InternalException(e); } } @Override public void suspend(@Nonnull String vmId) throws CloudException, InternalException { if (vmId == null) throw new InternalException("The id of the Virtual Machine to suspend cannot be null."); ProviderContext ctx = getProvider().getContext(); if (ctx == null) { throw new AzureConfigException("No context was set for this request"); } VirtualMachine vm = getVirtualMachine(vmId); if (vm == null) { throw new CloudException("No such virtual machine: " + vmId); } String resourceUrl = String.format(OPERATIONS_RESOURCES, vm.getTag("serviceName").toString(), vm.getTag("deploymentName").toString(), vm.getTag("roleName").toString()); AzureMethod azureMethod = new AzureMethod(getProvider()); Operation.ShutdownRoleOperation shutdownRoleOperation = new Operation.ShutdownRoleOperation(); shutdownRoleOperation.setPostShutdownAction("StoppedDeallocated"); try { azureMethod.post(resourceUrl, shutdownRoleOperation); } catch (JAXBException e) { logger.error(e.getMessage()); throw new InternalException(e); } } @Override public void terminate(@Nonnull String vmId, @Nullable String explanation) throws InternalException, CloudException { if (logger.isTraceEnabled()) { logger.trace("ENTER: " + AzureVM.class.getName() + ".terminate()"); } try { if (vmId == null) throw new InternalException("The id of the Virtual Machine to terminate cannot be null."); ProviderContext ctx = getProvider().getContext(); if (ctx == null) { throw new AzureConfigException("No context was set for this request"); } waitForVMTerminableState(vmId); AzureRoleDetails azureNames = AzureRoleDetails.fromString(vmId); String serviceName = azureNames.getServiceName(); String deploymentName = azureNames.getDeploymentName(); String roleName = azureNames.getRoleName(); if (canDeleteDeployment(serviceName, deploymentName, roleName)) { deleteVirtualMachineDeployment(vmId, serviceName, deploymentName, roleName); terminateService(serviceName, explanation); } else { deleteVirtualMachineRole(vmId, serviceName, deploymentName, roleName); } } finally { if (logger.isTraceEnabled()) { logger.trace("EXIT: " + AzureVM.class.getName() + ".terminate()"); } } } private boolean canDeleteDeployment(String serviceName, String deploymentName, String roleName) throws CloudException, InternalException { String deploymentUri = String.format(DEPLOYMENT_RESOURCE, getProvider().getContext().getCloud().getEndpoint(), getProvider().getContext().getAccountNumber(), serviceName, deploymentName); DeploymentModel deploymentModel = new DaseinRequest(getProvider(), getProvider().getAzureClientBuilder(), RequestBuilder.get().addHeader("x-ms-version", "2014-05-01").setUri(deploymentUri).build()) .withXmlProcessor(DeploymentModel.class).execute(); if (deploymentModel.getRoles() == null) return true; if (deploymentModel.getRoles().size() == 1 && deploymentModel.getRoles().get(0).getRoleName().equalsIgnoreCase(roleName)) return true; return false; } private void deleteVirtualMachineRole(String vmId, String serviceName, String deploymentName, String roleName) throws CloudException, InternalException { String resourceDir = HOSTED_SERVICES + "/" + serviceName + "/deployments/" + deploymentName + "/roles/" + roleName + "?comp=media"; AzureMethod method = new AzureMethod(getProvider()); method.invoke("DELETE", getProvider().getContext().getAccountNumber(), resourceDir, ""); waitForVMTerminated(vmId); } private void deleteVirtualMachineDeployment(String vmId, String serviceName, String deploymentName, String roleName) throws CloudException, InternalException { String resourceDir = HOSTED_SERVICES + "/" + serviceName + "/deployments/" + deploymentName + "?comp=media"; AzureMethod method = new AzureMethod(getProvider()); method.invoke("DELETE", getProvider().getContext().getAccountNumber(), resourceDir, ""); waitForVMTerminated(vmId); } private void waitForVMTerminableState(String vmId) throws CloudException, InternalException { VirtualMachine vm = getVirtualMachine(vmId); if (vm == null) { throw new CloudException("No such virtual machine: " + vmId); } long timeout = System.currentTimeMillis() + (CalendarWrapper.MINUTE * 10L); while (timeout > System.currentTimeMillis()) { if (vm == null || VmState.TERMINATED.equals(vm.getCurrentState())) { return; } if (!VmState.PENDING.equals(vm.getCurrentState()) && !VmState.STOPPING.equals(vm.getCurrentState())) { break; } try { Thread.sleep(15000L); } catch (InterruptedException ignore) { } try { vm = getVirtualMachine(vmId); } catch (Throwable ignore) { } } } private void waitForVMTerminated(String vmId) throws CloudException, InternalException { VirtualMachine vm = getVirtualMachine(vmId); long timeout = System.currentTimeMillis() + (CalendarWrapper.MINUTE * 10L); while (timeout > System.currentTimeMillis()) { if (vm == null || VmState.TERMINATED.equals(vm.getCurrentState())) { break; } try { Thread.sleep(15000L); } catch (InterruptedException ignore) { } try { vm = getVirtualMachine(vmId); } catch (Throwable ignore) { } } } private void waitForVMRunning(String vmId) throws CloudException, InternalException { VirtualMachine vm = getVirtualMachine(vmId); long timeout = System.currentTimeMillis() + (CalendarWrapper.MINUTE * 10L); while (timeout > System.currentTimeMillis()) { if (vm == null || VmState.RUNNING.equals(vm.getCurrentState())) { break; } try { Thread.sleep(15000L); } catch (InterruptedException ignore) { } try { vm = getVirtualMachine(vmId); } catch (Throwable ignore) { } } } public void terminateService(String serviceName, String explanation) throws InternalException, CloudException { APITrace.begin(getProvider(), "VM.terminateService"); try { ProviderContext ctx = getProvider().getContext(); if (ctx == null) { throw new AzureConfigException("No context was set for this request"); } AzureMethod method = new AzureMethod(getProvider()); String resourceDir = HOSTED_SERVICES + "/" + serviceName; long timeout = System.currentTimeMillis() + (CalendarWrapper.MINUTE * 10L); while (timeout > System.currentTimeMillis()) { try { if (logger.isInfoEnabled()) { logger.info("Deleting hosted service " + serviceName + ": " + explanation); } method.invoke("DELETE", ctx.getAccountNumber(), resourceDir, ""); break; } catch (CloudException e) { logger.error("Unable to delete hosted service for " + serviceName + ": " + e.getMessage()); logger.error("Retrying..."); try { Thread.sleep(30000L); } catch (InterruptedException ignore) { } continue; } catch (Throwable t) { logger.warn("Unable to delete hosted service for " + serviceName + ": " + t.getMessage()); return; } } } finally { APITrace.end(); } } private ArrayList<String> getAttachedDisks(VirtualMachine vm) throws InternalException, CloudException { ProviderContext ctx = getProvider().getContext(); if (ctx == null) { throw new AzureConfigException("No context was set for this request"); } ArrayList<String> list = new ArrayList<String>(); boolean diskFound = false; String serviceName, deploymentName; serviceName = vm.getTag("serviceName").toString(); deploymentName = vm.getTag("deploymentName").toString(); String resourceDir = HOSTED_SERVICES + "/" + serviceName + "/deployments/" + deploymentName; AzureMethod method = new AzureMethod(getProvider()); Document doc = method.getAsXML(ctx.getAccountNumber(), resourceDir); NodeList entries = doc.getElementsByTagName("Deployment"); for (int i = 0; i < entries.getLength(); i++) { Node entry = entries.item(i); NodeList attributes = entry.getChildNodes(); for (int j = 0; j < attributes.getLength(); j++) { Node attribute = attributes.item(j); if (attribute.getNodeName().equalsIgnoreCase("RoleList") && attribute.hasChildNodes()) { NodeList instances = attribute.getChildNodes(); for (int k = 0; k < instances.getLength(); k++) { Node instance = instances.item(k); if (instance.getNodeName().equalsIgnoreCase("Role") && instance.hasChildNodes()) { NodeList roles = instance.getChildNodes(); for (int l = 0; l < roles.getLength(); l++) { Node role = roles.item(l); if (role.getNodeName().equalsIgnoreCase("OSVirtualHardDisk") && role.hasChildNodes()) { NodeList disks = role.getChildNodes(); for (int m = 0; m < disks.getLength(); m++) { Node disk = disks.item(m); if (disk.getNodeName().equalsIgnoreCase("DiskName") && disk.hasChildNodes()) { String name = disk.getFirstChild().getNodeValue(); list.add(name); diskFound = true; break; } } } if (diskFound) { diskFound = false; break; } } } } } } } return list; } @Override public void unpause(@Nonnull String vmId) throws CloudException, InternalException { throw new OperationNotSupportedException("Pause/unpause is not supported in Microsoft Azure"); } @Override public void updateTags(@Nonnull String vmId, @Nonnull Tag... tags) throws CloudException, InternalException { //To change body of implemented methods use File | Settings | File Templates. } @Override public void updateTags(@Nonnull String[] strings, @Nonnull Tag... tags) throws CloudException, InternalException { //To change body of implemented methods use File | Settings | File Templates. } @Override public void removeTags(@Nonnull String s, @Nonnull Tag... tags) throws CloudException, InternalException { //To change body of implemented methods use File | Settings | File Templates. } @Override public void removeTags(@Nonnull String[] strings, @Nonnull Tag... tags) throws CloudException, InternalException { //To change body of implemented methods use File | Settings | File Templates. } @Override public @Nonnull String[] mapServiceAction(@Nonnull ServiceAction action) { return new String[0]; } private @Nonnull String toUniqueId(@Nonnull String name, @Nonnull AzureMethod method, ProviderContext ctx) throws CloudException, InternalException { name = name.toLowerCase().replaceAll(" ", ""); String id = name; int i = 0; while (method.getAsXML(ctx.getAccountNumber(), HOSTED_SERVICES + "/" + id) != null) { i++; id = name + "-" + i; } return id; } 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; } }