<commit_before>/**
 * 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.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.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 <NAME> (<EMAIL>)
 * @author <NAME>
 * @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 = "/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(Architecture.I64);
        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, Architecture.I64) ) {
            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.equals(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 = (options.getBootstrapUser() == null || (options.getBootstrapUser().isEmpty()) ? DEFAULT_USERNAME : 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, 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());
            return vm;
        }<commit_msg>Fix for password not set in launch method<commit_after>/**
 * 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.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.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 <NAME> (<EMAIL>)
 * @author <NAME>
 * @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 = "/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(Architecture.I64);
        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, Architecture.I64) ) {
            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.equals(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 = (options.getBootstrapUser() == null || (options.getBootstrapUser().isEmpty()) ? DEFAULT_USERNAME : 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, 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;
        }
{'fraction_non_alphanumeric': 0.11128834355828221, 'fraction_numerical': 0.0037627811860940696, 'mean_word_length': 1.8417596466759647, 'pattern_counts': {'":': 12, '<': 35, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 20}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 66, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7390055', 'n_tokens_mistral': 11988, 'n_tokens_neox': 11408, 'n_words': 2547}