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

org.dasein.cloud.cloudstack.compute.VirtualMachines Maven / Gradle / Ivy

Go to download

Implements the Dasein Cloud API for Cloud.com Cloudstack-based public and private clouds.

There is a newer version: 2015.10.5
Show newest version
/**
 * Copyright (C) 2009-2015 Dell, Inc.
 *
 * ====================================================================
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ====================================================================
 */

package org.dasein.cloud.cloudstack.compute;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.dasein.cloud.CloudException;
import org.dasein.cloud.InternalException;
import org.dasein.cloud.ProviderContext;
import org.dasein.cloud.Requirement;
import org.dasein.cloud.ResourceStatus;
import org.dasein.cloud.Tag;
import org.dasein.cloud.cloudstack.CSCloud;
import org.dasein.cloud.cloudstack.CSException;
import org.dasein.cloud.cloudstack.CSMethod;
import org.dasein.cloud.cloudstack.CSTopology;
import org.dasein.cloud.cloudstack.CSVersion;
import org.dasein.cloud.cloudstack.Param;
import org.dasein.cloud.cloudstack.network.Network;
import org.dasein.cloud.cloudstack.network.SecurityGroup;
import org.dasein.cloud.compute.*;
import org.dasein.cloud.network.RawAddress;
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.Hour;
import org.dasein.util.uom.time.TimePeriod;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;

public class VirtualMachines extends AbstractVMSupport {
    static public final Logger logger = Logger.getLogger(VirtualMachines.class);
    
    static private final String DEPLOY_VIRTUAL_MACHINE  = "deployVirtualMachine";
    static private final String DESTROY_VIRTUAL_MACHINE = "destroyVirtualMachine";
    static private final String GET_VIRTUAL_MACHINE_PASSWORD = "getVMPassword";
    static private final String LIST_VIRTUAL_MACHINES   = "listVirtualMachines";
    static private final String LIST_SERVICE_OFFERINGS  = "listServiceOfferings";
    static private final String REBOOT_VIRTUAL_MACHINE  = "rebootVirtualMachine";
    static private final String RESET_VIRTUAL_MACHINE_PASSWORD = "resetPasswordForVirtualMachine";
    static private final String RESIZE_VIRTUAL_MACHINE  = "scaleVirtualMachine";
    static private final String START_VIRTUAL_MACHINE   = "startVirtualMachine";
    static private final String STOP_VIRTUAL_MACHINE    = "stopVirtualMachine";
    
    static private Properties                              cloudMappings;
    static private Map>          customNetworkMappings;
    static private Map>>     customServiceMappings;
    
    public VirtualMachines(CSCloud provider) {
        super(provider);
    }

    @Override
    public VirtualMachine alterVirtualMachineSize( @Nonnull String vmId, @Nullable String cpuCount, @Nullable String ramInMB ) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "VM.alterVirtualMachineSize");
        try {
            VirtualMachine vm = getVirtualMachine(vmId);

            boolean restart = false;
            if (!vm.getCurrentState().equals(VmState.STOPPED)) {
                restart = true;
                stop(vmId, true);
            }

            long timeout = System.currentTimeMillis()+(CalendarWrapper.MINUTE*20L);
            while (System.currentTimeMillis() < timeout) {
                if (!vm.getCurrentState().equals(VmState.STOPPED)) {
                    try {
                        Thread.sleep(15000L);
                        vm = getVirtualMachine(vmId);
                    }
                    catch (InterruptedException ignore) {}
                }
                else {
                    break;
                }
            }
            vm = getVirtualMachine(vmId);
            if (!vm.getCurrentState().equals(VmState.STOPPED)) {
                throw new CloudException("Unable to stop vm for scaling");
            }
            List params = new ArrayList();
            params.add(new Param("id", vmId));
            params.add(new Param("serviceOfferingId", vm.getProductId()));
            int index = 0;
            if( cpuCount != null ) {
                params.add(new Param("details["+index+"].cpunumber", cpuCount));
                index++;
            }
            if( ramInMB != null ) {
                params.add(new Param("details["+index+"].memory", ramInMB));
            }
            Document doc = new CSMethod(getProvider()).get(RESIZE_VIRTUAL_MACHINE, params);

            NodeList matches = doc.getElementsByTagName("scalevirtualmachineresponse");
            String jobId = null;

            for( int i=0; i 0) {
                    Node virtualMachine = nodeList.item(0);
                    vm = toVirtualMachine(virtualMachine);
                    if( vm != null ) {
                        if (restart) {
                            start(vmId);
                        }
                        return vm;
                    }
                }
            }
            if (restart) {
                start(vmId);
            }
            return getVirtualMachine(vmId);
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public VirtualMachine alterVirtualMachineProduct(@Nonnull String vmId, @Nonnull String productId) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "VM.alterVirtualMachineProduct");
        try {
            VirtualMachine vm = getVirtualMachine(vmId);
            if (vm.getProductId().equals(productId)) {
                return vm;
            }

            boolean restart = false;
            if (!vm.getCurrentState().equals(VmState.STOPPED)) {
                restart = true;
                stop(vmId, true);
            }

            long timeout = System.currentTimeMillis()+(CalendarWrapper.MINUTE*20L);
            while (System.currentTimeMillis() < timeout) {
                if (!vm.getCurrentState().equals(VmState.STOPPED)) {
                    try {
                        Thread.sleep(15000L);
                        vm = getVirtualMachine(vmId);
                    }
                    catch (InterruptedException ignore) {}
                }
                else {
                    break;
                }
            }
            vm = getVirtualMachine(vmId);
            if (!vm.getCurrentState().equals(VmState.STOPPED)) {
                throw new CloudException("Unable to stop vm for scaling");
            }
            Document doc = new CSMethod(getProvider()).get(RESIZE_VIRTUAL_MACHINE,
                    new Param("id", vmId),
                    new Param("serviceOfferingId", productId));

            NodeList matches = doc.getElementsByTagName("scalevirtualmachineresponse");
            String jobId = null;

            for( int i=0; i 0) {
                    Node virtualMachine = nodeList.item(0);
                    vm = toVirtualMachine(virtualMachine);
                    if( vm != null ) {
                        if (restart) {
                            start(vmId);
                        }
                        return vm;
                    }
                }
            }
            if (restart) {
                start(vmId);
            }
            return getVirtualMachine(vmId);
        }
        finally {
            APITrace.end();
        }
    }

    private transient volatile VMCapabilities capabilities;
    @Nonnull
    @Override
    public VirtualMachineCapabilities getCapabilities() throws InternalException, CloudException {
        if( capabilities == null ) {
            capabilities = new VMCapabilities(getProvider());
        }
        return capabilities;
    }

    @Nullable
    @Override
    public VMScalingCapabilities describeVerticalScalingCapabilities() throws CloudException, InternalException {
        return VMScalingCapabilities.getInstance(false,true,Requirement.NONE,Requirement.NONE);
    }

    @Nullable
    @Override
    public String getPassword(@Nonnull String vmId) throws InternalException, CloudException {
        return getRootPassword(vmId);
    }

    private String getRootPassword(@Nonnull String serverId) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "VM.getPassword");
        try {
            Document doc = new CSMethod(getProvider()).get(GET_VIRTUAL_MACHINE_PASSWORD, new Param("id", serverId));

            if (doc != null){
                NodeList matches = doc.getElementsByTagName("getvmpasswordresponse");

                for( int i=0; i 0 ) {
                                value = attribute.getFirstChild().getNodeValue();
                            }
                            else {
                                value = null;
                            }
                            if( name.equals("password") ) {
                                NodeList nodes = attribute.getChildNodes();
                                for( int k=0; k 0 ) {
                                        value = password.getFirstChild().getNodeValue();
                                    }
                                    else {
                                        value = null;
                                    }
                                    if( name.equals("encryptedpassword") ) {
                                        return value;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            logger.warn("Unable to find password for vm with id "+serverId);
            return null;
        }
        catch (CSException e) {
            if (e.getHttpCode() == 431) {
                logger.warn("No password found for vm "+serverId);
            }
            return null;
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public @Nullable VirtualMachine getVirtualMachine(@Nonnull String serverId) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "VM.getVirtualMachine");
        try {
            Document doc = new CSMethod(getProvider()).get(LIST_VIRTUAL_MACHINES, new Param("id", serverId));
            NodeList matches = doc.getElementsByTagName("virtualmachine");

            if( matches.getLength() < 1 ) {
                return null;
            }
            for( int i=0; i tags = new ArrayList();
            Map meta = withLaunchOptions.getMetaData();
            for( Map.Entry entry : meta.entrySet() ) {
            	if( entry.getKey().equalsIgnoreCase("name") || entry.getKey().equalsIgnoreCase("description") ) {
            		continue;
            	}
            	if (entry.getValue() != null && !entry.getValue().equals("")) {
            		tags.add(new Tag(entry.getKey(), entry.getValue().toString()));
            	}
            }
            tags.add(new Tag("Name", withLaunchOptions.getFriendlyName()));
            tags.add(new Tag("Description", withLaunchOptions.getDescription()));
            if( withLaunchOptions.getVirtualMachineGroup() != null ) {
            	tags.add(new Tag("dsnVMGroup", withLaunchOptions.getVirtualMachineGroup()));
            }
            getProvider().createTags(new String[] { vm.getProviderVirtualMachineId() }, "UserVm", tags.toArray(new Tag[tags.size()]));
            return vm;
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    @Deprecated
    @SuppressWarnings("deprecation")
    public @Nonnull VirtualMachine launch(@Nonnull String imageId, @Nonnull VirtualMachineProduct product, @Nonnull String inZoneId, @Nonnull String name, @Nonnull String description, @Nullable String usingKey, @Nullable String withVlanId, boolean withMonitoring, boolean asSandbox, @Nullable String[] protectedByFirewalls, @Nullable Tag ... tags) throws InternalException, CloudException {
        if( getProvider().getVersion().greaterThan(CSVersion.CS21) ) {
            StringBuilder userData = new StringBuilder();
            
            if( tags != null && tags.length > 0 ) {
                for( Tag tag : tags ) {
                    userData.append(tag.getKey());
                    userData.append("=");
                    userData.append(tag.getValue());
                    userData.append("\n");
                }
            }
            else {
                userData.append("created=Dasein Cloud\n");
            }
            return launch22(imageId, product, inZoneId, name, usingKey, withVlanId, protectedByFirewalls, userData.toString());
        }
        else {
            return launch21(imageId, product, inZoneId, name);
        }
    }
    
    private VirtualMachine launch21(String imageId, VirtualMachineProduct product, String inZoneId, String name) throws InternalException, CloudException {
        return launch(new CSMethod(getProvider()).get(
                DEPLOY_VIRTUAL_MACHINE,
                new Param("zoneId", getContext().getRegionId()),
                new Param("serviceOfferingId", product.getProviderProductId()),
                new Param("templateId", imageId), new Param("displayName", name))
        );
    }
    
    private void load() {
        try {
            InputStream input = VirtualMachines.class.getResourceAsStream("/cloudMappings.cfg");
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            Properties properties = new Properties();
            String line;
            
            while( (line = reader.readLine()) != null ) {
                if( line.startsWith("#") ) {
                    continue;
                }
                int idx = line.indexOf('=');
                if( idx < 0 || line.endsWith("=") ) {
                    continue;
                }
                String cloudUrl = line.substring(0, idx);
                String cloudId = line.substring(idx+1);
                properties.put(cloudUrl, cloudId);
            }
            cloudMappings = properties;
        }
        catch( Throwable ignore ) {
            // ignore
        }        
        try {
            InputStream input = VirtualMachines.class.getResourceAsStream("/customNetworkMappings.cfg");
            Map> mapping = new HashMap>();
            Properties properties = new Properties();
            
            properties.load(input);
            for( Object key : properties.keySet() ) {
                String[] trueKey = ((String)key).split(",");
                Map current = mapping.get(trueKey[0]);
                
                if( current == null ) {
                    current = new HashMap();
                    mapping.put(trueKey[0], current);
                }
                current.put(trueKey[1], (String)properties.get(key));
            }
            customNetworkMappings = mapping;
        }
        catch( Throwable ignore ) {
            // ignore
        }
        try {
            InputStream input = VirtualMachines.class.getResourceAsStream("/customServiceMappings.cfg");
            Map>> mapping = new HashMap>>();
            Properties properties = new Properties();
            
            properties.load(input);
            
            for( Object key : properties.keySet() ) {
                String value = (String)properties.get(key);
                
                if( value != null ) {
                    String[] trueKey = ((String)key).split(",");
                    Map> tmp = mapping.get(trueKey[0]);
                    
                    if( tmp == null ) {
                        tmp =new HashMap>();
                        mapping.put(trueKey[0], tmp);
                    }
                    TreeSet m = new TreeSet();
                    String[] offerings = value.split(",");
                    
                    if( offerings == null || offerings.length < 1 ) {
                        m.add(value);
                    }
                    else {
                        Collections.addAll(m, offerings);
                    }
                    tmp.put(trueKey[1], m);
                }
            }
            customServiceMappings = mapping;
        }
        catch( Throwable ignore ) {
            // ignore
        }
    }
    
    private @Nonnull VirtualMachine launch22(@Nonnull String imageId, @Nonnull VirtualMachineProduct product, @Nullable String inZoneId, @Nonnull String name, @Nullable String withKeypair, @Nullable String targetVlanId, @Nullable String[] protectedByFirewalls, @Nullable String userData) throws InternalException, CloudException {
        ProviderContext ctx = getContext();
        List vlans = null;

        if( ctx == null ) {
            throw new InternalException("No context was provided for this request");
        }
        String regionId = ctx.getRegionId();

        if( inZoneId == null || inZoneId.isEmpty() ) {
            inZoneId = regionId;
        }

        if( inZoneId == null || inZoneId.isEmpty() ) {
            throw new InternalException("No region is established for this request");
        }

       String prdId = product.getProviderProductId();

        if( customNetworkMappings == null ) {
            load();
        }
        if( customNetworkMappings != null ) {
            String cloudId = cloudMappings.getProperty(ctx.getCloud().getEndpoint());
            
            if( cloudId != null ) {
                Map map = customNetworkMappings.get(cloudId);
                
                if( map != null ) {
                    String id = map.get(prdId);
                    
                    if( id != null ) {
                        targetVlanId = id;
                    }
                }
            }
        }
        if( targetVlanId != null && targetVlanId.length() < 1 ) {
            targetVlanId = null;
        }
        if( userData == null ) {
            userData = "";
        }

        String securityGroupIds = StringUtils.join(protectedByFirewalls, ",");

        if( targetVlanId == null ) {
            Network vlan = getProvider().getNetworkServices().getVlanSupport();
            
            if( vlan != null && vlan.isSubscribed() ) {
                if( getCapabilities().identifyVlanRequirement().equals(Requirement.REQUIRED) ) {
                    vlans = vlan.findFreeNetworks();
                }
            }
        }
        else {
            vlans = new ArrayList();
            vlans.add(targetVlanId);
        }
        if( securityGroupIds != null && !securityGroupIds.isEmpty() ) {
            // TODO: shouldn't we throw OpNotSupported if firewalls aren't supported but still requested?
            // otherwise it's like a confusion, no?
            if (!getProvider().getDataCenterServices().supportsSecurityGroups(regionId, vlans == null || vlans.isEmpty())) {
                securityGroupIds = null;
            }
        }
        else if( getProvider().getDataCenterServices().supportsSecurityGroups(regionId, vlans == null || vlans.isEmpty()) ) {
            /*
            String sgId = null;
            
            if( withVlanId == null ) {
                Collection firewalls = getProvider().getNetworkServices().getFirewallSupport().list();
                
                for( Firewall fw : firewalls ) {
                    if( fw.getName().equalsIgnoreCase("default") && fw.getProviderVlanId() == null ) {
                        sgId = fw.getProviderFirewallId();
                        break;
                    }
                }
                if( sgId == null ) {
                    try {
                        sgId = getProvider().getNetworkServices().getFirewallSupport().create("default", "Default security group");
                    }
                    catch( Throwable t ) {
                        logger.warn("Unable to create a default security group, gonna try anyways: " + t.getMessage());
                    }
                }
                if( sgId != null ) {
                    securityGroupIds = sgId;
                }
            }
            else {
                Collection firewalls = getProvider().getNetworkServices().getFirewallSupport().list();
                
                for( Firewall fw : firewalls ) {
                    if( (fw.getName().equalsIgnoreCase("default") || fw.getName().equalsIgnoreCase("default-" + withVlanId)) && withVlanId.equals(fw.getProviderVlanId()) ) {
                        sgId = fw.getProviderFirewallId();
                        break;
                    }
                }
                if( sgId == null ) {
                    try {
                        sgId = getProvider().getNetworkServices().getFirewallSupport().createInVLAN("default-" + withVlanId, "Default " + withVlanId + " security group", withVlanId);
                    }
                    catch( Throwable t ) {
                        logger.warn("Unable to create a default security group, gonna try anyways: " + t.getMessage());
                    }
                }
            }
            if( sgId != null ) {
                securityGroupIds = sgId;
                count++;
            }    
            */            
        }
        List params = new ArrayList();
        params.add(new Param("zoneId", inZoneId));
        params.add(new Param("serviceOfferingId", prdId));
        params.add(new Param("templateId", imageId));
        params.add(new Param("displayName", name));
        if( userData != null && userData.length() > 0 ) {
            try {
                params.add(new Param("userdata", new String(Base64.encodeBase64(userData.getBytes("utf-8")), "utf-8")));
            }
            catch( UnsupportedEncodingException e ) {
//                e.printStackTrace();
            }
        }
        if( withKeypair != null ) {
            params.add(new Param("keypair", withKeypair));
        }
        if( securityGroupIds != null && securityGroupIds.length() > 0 ) {
            params.add(new Param("securitygroupids", securityGroupIds));
        }
        if( vlans != null && vlans.size() > 0 ) {
            CloudException lastError = null;

            for( String withVlanId : vlans ) {
                params.add(new Param("networkIds", withVlanId));

                try {
                    return launch(new CSMethod(getProvider()).get(
                            DEPLOY_VIRTUAL_MACHINE,
                            params.toArray(new Param[params.size()]))
                    );
                }
                catch( CloudException e ) {
                    if( e.getMessage().contains("sufficient address capacity") ) {
                        lastError = e;
                        continue;
                    }
                    throw e;
                }
            }
            if( lastError == null ) {
                throw lastError;
            }
            throw new CloudException("Unable to identify a network into which a VM can be launched");
        }
        else {
            return launch(new CSMethod(getProvider()).get(
                    DEPLOY_VIRTUAL_MACHINE,
                    params.toArray(new Param[params.size()])
            ));
        }
    }
    
    private @Nonnull VirtualMachine launch(@Nonnull Document doc) throws InternalException, CloudException {
        NodeList matches = doc.getElementsByTagName("deployvirtualmachineresponse");
        String serverId = null;
        String jobId = null;
        
        for( int i=0; i 0) {
                Node virtualMachine = nodeList.item(0);
                vm = toVirtualMachine(virtualMachine);
                if( vm != null ) {
                    return vm;
                }
            }
        }
        
        if (vm == null){
        	vm = getVirtualMachine(serverId);
        }
        if( vm == null ) {
            throw new CloudException("No virtual machine provided: " + serverId);
        }
        return vm;
    }

    @Override
    public @Nonnull Iterable listFirewalls(@Nonnull String vmId) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "VM.listFirewalls");
        try {
            SecurityGroup support = getProvider().getNetworkServices().getFirewallSupport();

            if( support == null ) {
                return Collections.emptyList();
            }
            return support.listFirewallsForVM(vmId);
        }
        finally {
            APITrace.end();
        }
    }

    private void setFirewalls(@Nonnull VirtualMachine vm) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "VM.setFirewalls");
        try {
            SecurityGroup support = getProvider().getNetworkServices().getFirewallSupport();

            if( support == null ) {
                return;
            }
            List ids = new ArrayList();

            for( String id : support.listFirewallsForVM(vm.getProviderVirtualMachineId()) ) {
                ids.add(id);
            }
            vm.setProviderFirewallIds(ids.toArray(new String[ids.size()]));
        }
        finally {
            APITrace.end();
        }
    }

    @Nonnull
    @Override
    public Iterable listProducts(@Nonnull String machineImageId, @Nonnull VirtualMachineProductFilterOptions options) throws InternalException, CloudException {
        // all CS products are dual architecture so it doesn't matter which arch to choose
        return listProducts(options, Architecture.I64);
    }

    @Override
    public Iterable listProducts(VirtualMachineProductFilterOptions options, Architecture architecture) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "VM.listProducts");
        try {
            Cache cache = Cache.getInstance(getProvider(), "ServerProducts", VirtualMachineProduct.class, CacheLevel.REGION_ACCOUNT, new TimePeriod(4, TimePeriod.HOUR));
            Collection products = (Collection)cache.get(getContext());
            if(products == null){
                Set mapping = null;

                if( customServiceMappings == null ) {
                    load();
                }
                if( customServiceMappings != null ) {
                    String cloudId = cloudMappings.getProperty(getContext().getCloud().getEndpoint());

                    if( cloudId != null ) {
                        Map> map = customServiceMappings.get(cloudId);

                        if( map != null ) {
                            mapping = map.get(getContext().getRegionId());
                        }
                    }
                }
                products = new ArrayList();

                Document doc = new CSMethod(getProvider()).get(
                        LIST_SERVICE_OFFERINGS,
                        new Param("zoneId", getContext().getRegionId())
                );
                NodeList matches = doc.getElementsByTagName("serviceoffering");

                for( int i=0; i 0 ) {
                            value = n.getFirstChild().getNodeValue();
                        }
                        else {
                            value = null;
                        }
                        if( n.getNodeName().equals("id") ) {
                            id = value;
                        }
                        else if( n.getNodeName().equals("name") ) {
                            name = value;
                        }
                        else if( n.getNodeName().equals("cpunumber") ) {
                            cpu = Integer.parseInt(value);
                        }
                        else if( n.getNodeName().equals("memory") ) {
                            memory = Integer.parseInt(value);
                        }
                        else if( n.getNodeName().equals("iscustomized") ) {
                            customized = Boolean.valueOf(value);
                        }
                        if( id != null && name != null && cpu > 0 && memory > 0 && customized != null) {
                            break;
                        }
                    }
                    if( id != null  && name != null && cpu > 0 && memory > 0 && !customized) {
                        if( mapping == null || mapping.contains(id) ) {
                            VirtualMachineProduct product;

                            product = new VirtualMachineProduct();
                            product.setProviderProductId(id);
                            product.setName(name + " (" + cpu + " CPU/" + memory + "MB RAM)");
                            product.setDescription(name + " (" + cpu + " CPU/" + memory + "MB RAM)");
                            product.setRamSize(new Storage(memory, Storage.MEGABYTE));
                            product.setCpuCount(cpu);
                            product.setRootVolumeSize(new Storage(1, Storage.GIGABYTE));
                            product.setArchitectures(Architecture.I32, Architecture.I64);
                            if (options != null) {
                                if (options.matches(product)) {
                                    products.add(product);
                                }
                            }
                            else {
                                products.add(product);
                            }
                        }
                    }
                }
                cache.put(getContext(), products);
            }
            return products;
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public @Nonnull Iterable listVirtualMachineStatus() throws InternalException, CloudException {
        APITrace.begin(getProvider(), "VM.listVirtualMachineStatus");
        try {
            CSMethod method = new CSMethod(getProvider());
            Document doc = method.get(
                    LIST_VIRTUAL_MACHINES,
                    new Param("zoneId", getContext().getRegionId())
            );
            List servers = new ArrayList();

            int numPages = 1;
            NodeList nodes = doc.getElementsByTagName("count");
            Node n = nodes.item(0);
            if (n != null) {
                String value = n.getFirstChild().getNodeValue().trim();
                int count = Integer.parseInt(value);
                numPages = count/500;
                int remainder = count % 500;
                if (remainder > 0) {
                    numPages++;
                }
            }

            for (int page = 1; page <= numPages; page++) {
                if (page > 1) {
                    String nextPage = String.valueOf(page);
                    doc = method.get(
                            LIST_VIRTUAL_MACHINES,
                            new Param("zoneId", getContext().getRegionId()),
                            new Param("pagesize", "500"),
                            new Param("page", nextPage)
                    );
                }
                NodeList matches = doc.getElementsByTagName("virtualmachine");

                for( int i=0; i listVirtualMachines() throws InternalException, CloudException {
        APITrace.begin(getProvider(), "VM.listVirtualMachines");
        try {
            CSMethod method = new CSMethod(getProvider());
            Document doc = method.get(
                    LIST_VIRTUAL_MACHINES,
                    new Param("zoneId", getContext().getRegionId())
            );
            List servers = new ArrayList();

            int numPages = 1;
            NodeList nodes = doc.getElementsByTagName("count");
            Node n = nodes.item(0);
            if (n != null) {
                String value = n.getFirstChild().getNodeValue().trim();
                int count = Integer.parseInt(value);
                numPages = count/500;
                int remainder = count % 500;
                if (remainder > 0) {
                    numPages++;
                }
            }

            for (int page = 1; page <= numPages; page++) {
                if (page > 1) {
                    String nextPage = String.valueOf(page);
                    doc = method.get(
                            LIST_VIRTUAL_MACHINES,
                            new Param("zoneId", getContext().getRegionId()),
                            new Param("pagesize", "500"),
                            new Param("page", nextPage));
                }
                NodeList matches = doc.getElementsByTagName("virtualmachine");

                for( int i=0; i 0 ) {
                                value = attribute.getFirstChild().getNodeValue();
                            }
                            else {
                                value = null;
                            }
                            if( name.equals("password") ) {
                                return value;
                            }
                        }
                    }
                }
            }


            logger.warn("Unable to find password for vm with id "+serverId);
            return null;
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public void reboot(@Nonnull String serverId) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "VM.reboot");
        try {
            new CSMethod(getProvider()).get(
                    REBOOT_VIRTUAL_MACHINE,
                    new Param("id", serverId)
            );
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public void start(@Nonnull String serverId) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "VM.start");
        try {
            new CSMethod(getProvider()).get(
                    START_VIRTUAL_MACHINE,
                    new Param("id", serverId)
            );
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public void stop(@Nonnull String vmId, boolean force) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "VM.stop");
        try {
            new CSMethod(getProvider()).get(
                    STOP_VIRTUAL_MACHINE,
                    new Param("id", vmId),
                    new Param("forced", String.valueOf(force))
            );
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public void terminate(@Nonnull String serverId, @Nullable String explanation) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "VM.terminate");
        try {
            List params = new ArrayList();
            params.add(new Param("id", serverId));
            if( getProvider().isAdminAccount() ) {
                params.add(new Param("expunge", "true"));
            }
            new CSMethod(getProvider()).get(
                    DESTROY_VIRTUAL_MACHINE, params
            );
        }
        finally {
            APITrace.end();
        }
    }

    private @Nullable ResourceStatus toStatus(@Nullable Node node) throws CloudException, InternalException {
        if( node == null ) {
            return null;
        }
        NodeList attributes = node.getChildNodes();
        VmState state = null;
        String serverId = null;

        for( int i=0; i 0 ) {
                value = attribute.getFirstChild().getNodeValue();
            }
            else {
                value = null;
            }
            if( name.equals("virtualmachineid") || name.equals("id") ) {
                serverId = value;
            }
            else if( name.equals("state") ) {
                if( value == null || value.equalsIgnoreCase("starting") || value.equalsIgnoreCase("creating") ) {
                    state = VmState.PENDING;
                }
                else  if( value.equalsIgnoreCase("stopped") ) {
                    state = VmState.STOPPED;
                }
                else if( value.equalsIgnoreCase("running") ) {
                    state = VmState.RUNNING;
                }
                else if( value.equalsIgnoreCase("stopping") ) {
                    state = VmState.STOPPING;
                }
                else if( value.equalsIgnoreCase("migrating") || value.equalsIgnoreCase("ha") ) {
                    state = VmState.REBOOTING;
                }
                else if( value.equalsIgnoreCase("destroyed") || value.equalsIgnoreCase("expunging") ) {
                    state = VmState.TERMINATED;
                }
                else if( value.equalsIgnoreCase("error") ) {
                    state = VmState.ERROR;
                }
                else {
                    throw new CloudException("Unexpected server state: " + value);
                }
            }
            if( serverId != null && state != null ) {
                break;
            }
        }
        if( serverId == null ) {
            return null;
        }
        if( state == null ) {
            state = VmState.PENDING;
        }
        return new ResourceStatus(serverId, state);
    }

    private @Nullable VirtualMachine toVirtualMachine(@Nullable Node node) throws CloudException, InternalException {
        if( node == null ) {
            return null;
        }
        HashMap properties = new HashMap();
        VirtualMachine server = new VirtualMachine();
        NodeList attributes = node.getChildNodes();
        String productId = null;
        
        server.setProviderOwnerId(getContext().getAccountNumber());
        server.setClonable(false);
        server.setImagable(false);
        server.setPausable(true);
        server.setPersistent(true);
        server.setArchitecture(Architecture.I64);
        for( int i=0; i 0 ) {
                value = attribute.getFirstChild().getNodeValue();                
            }
            else {
                value = null;
            }
            if( name.equals("virtualmachineid") || name.equals("id") ) {
                server.setProviderVirtualMachineId(value);                
            }
            else if( name.equals("name") ) {
                server.setDescription(value);
            }
            /*
            else if( name.equals("haenable") ) {
                server.setPersistent(value != null && value.equalsIgnoreCase("true"));
            }
            */
            else if( name.equals("displayname") ) {
                server.setName(value);
            }
            else if( name.equals("ipaddress") ) { // v2.1
                if( value != null ) {
                    server.setPrivateAddresses(new RawAddress(value));
                }
                server.setPrivateDnsAddress(value);
            }
            else if( name.equals("password") ) {
                server.setRootPassword(value);
            }
            else if( name.equals("securitygroup") ) { // v2.2+
                if( attribute.hasChildNodes() ) {
                    NodeList parts = attribute.getChildNodes();
                    String sgId = null, sgName = null, sgDescription = null;
                    for( int j=0; j 31 ) {
                                            pub = true;
                                        }
                                    }
                                    catch( NumberFormatException ignore ) {
                                        // ignore
                                    }
                                }
                            }
                            else {
                                pub = true;
                            }
                        }
                        if( pub ) {
                            server.setPublicAddresses(new RawAddress(addr));
                            if( server.getPublicDnsAddress() == null ) {
                                server.setPublicDnsAddress(addr);
                            }
                        }
                        else {
                            server.setPrivateAddresses(new RawAddress(addr));
                            if( server.getPrivateDnsAddress() == null ) {
                                server.setPrivateDnsAddress(addr);
                            }
                        }
                    }
                }
            }
            else if( name.equals("osarchitecture") ) {
                if( value != null && value.equals("32") ) {
                    server.setArchitecture(Architecture.I32);
                }
                else {
                    server.setArchitecture(Architecture.I64);                  
                }
            }
            else if( name.equals("created") ) {
                DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); //2009-02-03T05:26:32.612278
                
                try {
                    server.setCreationTimestamp(df.parse(value).getTime());
                }
                catch( ParseException e ) {
                    logger.warn("Invalid date: " + value);
                    server.setLastBootTimestamp(0L);
                }
            }
            else if( name.equals("state") ) {
                VmState state;

                //(Running, Stopped, Stopping, Starting, Creating, Migrating, HA).
                if( value.equalsIgnoreCase("stopped") ) {
                    state = VmState.STOPPED;
                    server.setImagable(true);
                }
                else if( value.equalsIgnoreCase("running") ) {
                    state = VmState.RUNNING;
                }
                else if( value.equalsIgnoreCase("stopping") ) {
                    state = VmState.STOPPING;
                }
                else if( value.equalsIgnoreCase("starting") ) {
                    state = VmState.PENDING;
                }
                else if( value.equalsIgnoreCase("creating") ) {
                    state = VmState.PENDING;
                }
                else if( value.equalsIgnoreCase("migrating") ) {
                    state = VmState.REBOOTING;
                }
                else if( value.equalsIgnoreCase("destroyed") ) {
                    state = VmState.TERMINATED;
                }
                else if( value.equalsIgnoreCase("error") ) {
                    state = VmState.ERROR;
                }
                else if( value.equalsIgnoreCase("expunging") ) {
                    state = VmState.TERMINATED;
                }
                else if( value.equalsIgnoreCase("ha") ) {
                    state = VmState.REBOOTING;
                }
                else {
                    throw new CloudException("Unexpected server state: " + value);
                }
                server.setCurrentState(state);                
            }
            else if( name.equals("zoneid") ) {
                server.setProviderRegionId(value);
                server.setProviderDataCenterId(value);
            }
            else if( name.equals("templateid") ) {
                server.setProviderMachineImageId(value);
            }
            else if( name.equals("templatename") ) {
                server.setPlatform(Platform.guess(value));
            }
            else if( name.equals("serviceofferingid") ) {
                productId = value;
            }
            else if( name.equals("keypair") ) {
                server.setProviderKeypairId(value);
            }
            else if( value != null ) {
                properties.put(name, value);
            }
        }
        if( server.getName() == null ) {
            server.setName(server.getProviderVirtualMachineId());
        }
        if( server.getDescription() == null ) {
            server.setDescription(server.getName());
        }
        server.setProviderAssignedIpAddressId(null);
        if( server.getProviderRegionId() == null ) {
            server.setProviderRegionId(getContext().getRegionId());
        }
        if( server.getProviderDataCenterId() == null ) {
            server.setProviderDataCenterId(getContext().getRegionId());
        }
        if( productId != null ) {
            server.setProductId(productId);
        }

        /*final String finalServerId = server.getProviderVirtualMachineId();
        // commenting out for now until we can find a way to return plain text rather than encrypted
            server.setPasswordCallback(new Callable() {
            @Override
            public String call() throws Exception {
                return getRootPassword(finalServerId);
            }
        }
        );  */
        server.setTags(properties);
        return server;
    }
    
    @Override
    public void setTags(@Nonnull String vmId, @Nonnull Tag... tags) throws CloudException, InternalException {
    	setTags(new String[] { vmId }, tags);
    }
    
    @Override
    public void setTags(@Nonnull String[] vmIds, @Nonnull Tag... tags) throws CloudException, InternalException {
    	APITrace.begin(getProvider(), "Server.setTags");
    	try {
    		removeTags(vmIds);
    		getProvider().createTags(vmIds, "UserVm", tags);
    	}
    	finally {
    		APITrace.end();
    	}
    }
    
    @Override
    public void updateTags(@Nonnull String vmId, @Nonnull Tag... tags) throws CloudException, InternalException {
    	updateTags(new String[] { vmId }, tags);
    }
    
    @Override
    public void updateTags(@Nonnull String[] vmIds, @Nonnull Tag... tags) throws CloudException, InternalException {
    	APITrace.begin(getProvider(), "Server.updateTags");
    	try {
    		getProvider().updateTags(vmIds, "UserVm", tags);
    	}
    	finally {
    		APITrace.end();
    	}
    }
    
    @Override
    public void removeTags(@Nonnull String vmId, @Nonnull Tag... tags) throws CloudException, InternalException {
    	removeTags(new String[] { vmId }, tags);
    }
    
    @Override
    public void removeTags(@Nonnull String[] vmIds, @Nonnull Tag... tags) throws CloudException, InternalException {
    	APITrace.begin(getProvider(), "Server.removeTags");
    	try {
    		getProvider().removeTags(vmIds, "UserVm", tags);
    	}
    	finally {
    		APITrace.end();
    	}
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy