com.abiquo.nodecollector.domain.collectors.HyperVCollector.java Source code

Java tutorial

Introduction

Here is the source code for com.abiquo.nodecollector.domain.collectors.HyperVCollector.java

Source

/**
 * Abiquo community edition
 * cloud management application for hybrid clouds
 * Copyright (C) 2008-2010 - Abiquo Holdings S.L.
 *
 * This application is free software; you can redistribute it and/or
 * modify it under the terms of the GNU LESSER GENERAL PUBLIC
 * LICENSE as published by the Free Software Foundation under
 * version 3 of the License
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * LESSER GENERAL PUBLIC LICENSE v.3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
package com.abiquo.nodecollector.domain.collectors;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.xml.xpath.XPathExpressionException;

import jcifs.smb.SmbException;

import org.apache.commons.lang.StringUtils;
import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.core.JIArray;
import org.jinterop.dcom.core.JIString;
import org.jinterop.dcom.core.JIVariant;
import org.jinterop.dcom.impls.JIObjectFactory;
import org.jinterop.dcom.impls.automation.IJIDispatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.abiquo.model.enumerator.HypervisorType;
import com.abiquo.nodecollector.aim.WsmanCollector;
import com.abiquo.nodecollector.aim.impl.WsmanCollectorImpl;
import com.abiquo.nodecollector.constants.MessageValues;
import com.abiquo.nodecollector.domain.Collector;
import com.abiquo.nodecollector.domain.collectors.hyperv.HyperVConstants;
import com.abiquo.nodecollector.domain.collectors.hyperv.HyperVState;
import com.abiquo.nodecollector.domain.collectors.hyperv.HyperVUtils;
import com.abiquo.nodecollector.domain.collectors.hyperv.MsvmImageManagementService;
import com.abiquo.nodecollector.domain.collectors.hyperv.Win32Process;
import com.abiquo.nodecollector.domain.collectors.hyperv.WindowsRegistry;
import com.abiquo.nodecollector.exception.CollectorException;
import com.abiquo.nodecollector.exception.ConnectionException;
import com.abiquo.nodecollector.exception.LoginException;
import com.abiquo.nodecollector.exception.NoManagedException;
import com.abiquo.nodecollector.exception.libvirt.WsmanException;
import com.abiquo.nodecollector.utils.ResourceComparator;
import com.abiquo.nodecollector.utils.XPathUtils;
import com.abiquo.server.core.infrastructure.nodecollector.HostDto;
import com.abiquo.server.core.infrastructure.nodecollector.HostStatusEnumType;
import com.abiquo.server.core.infrastructure.nodecollector.ResourceEnumType;
import com.abiquo.server.core.infrastructure.nodecollector.ResourceType;
import com.abiquo.server.core.infrastructure.nodecollector.VirtualDiskEnumType;
import com.abiquo.server.core.infrastructure.nodecollector.VirtualSystemCollectionDto;
import com.abiquo.server.core.infrastructure.nodecollector.VirtualSystemDto;
import com.abiquo.server.core.infrastructure.nodecollector.VirtualSystemStatusEnumType;
import com.hyper9.jwbem.SWbemLocator;
import com.hyper9.jwbem.SWbemServices;
import com.hyper9.jwbem.msvm.virtualsystem.MsvmSummaryInformation;
import com.hyper9.jwbem.msvm.virtualsystem.MsvmVirtualSystemSettingData;
import com.hyper9.jwbem.msvm.virtualsystemmanagement.MsvmVirtualSystemManagementService;

/**
 * Collects information of an Hyper-V node.
 * 
 * @author ibarrera
 */
@Collector(type = HypervisorType.HYPERV_301, order = 2)
public class HyperVCollector extends AbstractCollector {
    /** The logger. */
    private static final Logger LOGGER = LoggerFactory.getLogger(HyperVCollector.class);

    /** The SWbem service for the virtualization namespace. */
    private transient SWbemServices virtService;

    /** The SWbem service for the CIM namespace. */
    private transient SWbemServices cimService;

    /** The Windows Registry management service. */
    private transient WindowsRegistry registry;

    /** Connection user. */
    private String hyperVuser;

    /** Connection password. */
    private String hyperVpassword;

    // Could this be at AbstractCollector? (XenServerIncompatible)
    /** Folder mark perfix. */
    private static String DATASTORE_UUID_MARK = "abq_datastoreuuid_";

    private static String STANDARD_DISKS_KEY = "STANDARD_DISKS";

    private static String VOLUME_DISKS_KEY = "VOLUME_DISKS";

    @Override
    public void connect(final String user, final String password) throws ConnectionException, LoginException {
        hyperVuser = user;
        hyperVpassword = password;

        registry = new WindowsRegistry();

        try {
            final URL urlAddress = new URL("http://" + getIpAddress());
            final SWbemLocator loc = new SWbemLocator();
            cimService = loc.connect(urlAddress.getHost(), "127.0.0.1", HyperVConstants.CIM_NS, hyperVuser,
                    hyperVpassword);
        } catch (UnknownHostException e) {
            throw new ConnectionException(MessageValues.CONN_EXCP_I, e);
        } catch (JIException e) {
            // Error code '5' means the access is not allowed.
            if (e.getErrorCode() == 5) {
                throw new LoginException(MessageValues.LOG_EXCP, e);
            }
            throw new ConnectionException(MessageValues.CONN_EXCP_I, e);
        } catch (MalformedURLException e) {
            throw new ConnectionException(MessageValues.CONN_EXCP_I, e);
        }

    }

    @Override
    public void disconnect() {
        LOGGER.info("Disconnecting...");

        // The cimService can be null if the previous session was not authenticated.
        if (cimService != null) {
            cimService.getLocator().disconnect();
            if (virtService != null) {
                virtService.getLocator().disconnect();
            }
        }
    }

    @Override
    public HostDto getHostInfo() throws CollectorException {
        LOGGER.info("Getting physical information in HyperV collector...");
        final HostDto hostInfo = new HostDto();
        try {
            final List<IJIDispatch> results = HyperVUtils.execQuery("Select * from Win32_ComputerSystem",
                    cimService);
            final IJIDispatch dispatch = results.get(0);

            // Must produce only one result final
            JIVariant name = dispatch.get("DNSHostName");
            final JIVariant memory = dispatch.get("TotalPhysicalMemory");
            hostInfo.setName(name.getObjectAsString2());
            hostInfo.setRam(Long.decode(memory.getObjectAsString2()));
            hostInfo.setCpu(getNumberOfCores());
            hostInfo.setHypervisor(getHypervisorType().getValue());
            hostInfo.setVersion(getVersion());
            hostInfo.setInitiatorIQN(getInitiatorIQN(name.getObjectAsString2()));

            // Uncomment if you want to return physical
            // interfaces
            // final List<IJIDispatch> resultsIfaces =
            // HyperVUtils.execQuery("Select * from Win32_NetworkAdapter", cimService);
            // final List<IJIDispatch> resultsIfaces
            // =HyperVUtils.execQuery("Select * from Msvm_ExternalEthernetPort", cimService);
            // hostInfo.getResources().addAll(filterInterfaceList(resultsIfaces));

            URL urlAddress = new URL("http://" + getIpAddress());
            SWbemLocator loc = new SWbemLocator();
            virtService = loc.connect(urlAddress.getHost(), "127.0.0.1", HyperVConstants.VIRTUALIZATION_NS,
                    hyperVuser, hyperVpassword);

            hostInfo.getResources().addAll(getHostResources());

            try {
                checkPhysicalState();
                hostInfo.setStatus(HostStatusEnumType.MANAGED);
            } catch (NoManagedException e) {
                hostInfo.setStatus(HostStatusEnumType.NOT_MANAGED);
                hostInfo.setStatusInfo(e.getMessage());
            }
        } catch (Exception ex) {
            if (ex.getCause() instanceof SmbException) {
                LOGGER.error(MessageValues.COLL_EXCP_SMB);
                throw new CollectorException(MessageValues.COLL_EXCP_SMB, ex);
            }
            LOGGER.error(MessageValues.COLL_EXCP_PH);
            throw new CollectorException(MessageValues.COLL_EXCP_PH, ex);
        }
        return hostInfo;
    }

    @Override
    public VirtualSystemCollectionDto getVirtualMachines() throws CollectorException {
        LOGGER.info("Getting virtual machine information in HyperV collector...");

        VirtualSystemCollectionDto vms = new VirtualSystemCollectionDto();
        try {
            URL urlAddress = new URL("http://" + getIpAddress());
            SWbemLocator loc = new SWbemLocator();
            virtService = loc.connect(urlAddress.getHost(), "127.0.0.1", HyperVConstants.VIRTUALIZATION_NS,
                    hyperVuser, hyperVpassword);
            List<IJIDispatch> results = HyperVUtils
                    .execQuery("Select * from Msvm_ComputerSystem where ElementName <> Name", virtService);
            for (IJIDispatch dispatch : results) {
                String uuid = dispatch.get("Name").getObjectAsString2();
                String name = dispatch.get("ElementName").getObjectAsString2();
                LOGGER.info("Found virtual machine {}. Getting info...", name);

                int status = dispatch.get("EnabledState").getObjectAsInt();
                VirtualSystemStatusEnumType vmStatus = HyperVUtils.translateState(status);
                if (vmStatus != null) {
                    final VirtualSystemDto vm = new VirtualSystemDto();
                    vm.setUuid(uuid);
                    vm.setName(name);
                    vm.getResources().addAll(getDisksInfo(dispatch));
                    vm.setCpu(getVirtualProcessors(dispatch));
                    vm.setVport(0L);
                    vm.setStatus(vmStatus);
                    long virtualMemory = getVirtualMemory(uuid);
                    if (virtualMemory != -1) {
                        vm.setRam(virtualMemory);
                    }
                    vms.getVirtualSystems().add(vm);
                } else {
                    LOGGER.info("Ignoring found virtual machine {}. State {} not recognized.", name, status);
                }
            }
        } catch (Exception ex) {
            throw new CollectorException(MessageValues.COLL_EXCP_VM, ex);
        }
        return vms;
    }

    /**
     * Gets the physical state of the node.
     * 
     * @throws CollectorException When the Node Collector cannot connect to the Hypervisor.
     * @throws NoManagedException if the HyperV is running but not prepared for manage with abicloud
     */

    public void checkPhysicalState() throws CollectorException, NoManagedException {
        try {
            URL urlAddress = new URL("http://" + getIpAddress());
            SWbemLocator loc = new SWbemLocator();
            final WsmanCollector wsmanColl = new WsmanCollectorImpl(hyperVuser, hyperVpassword, 5985);
            wsmanColl.pingWsmanService(urlAddress.getHost());

            virtService = loc.connect(urlAddress.getHost(), "127.0.0.1", HyperVConstants.VIRTUALIZATION_NS,
                    hyperVuser, hyperVpassword);
            List<IJIDispatch> results = HyperVUtils
                    .execQuery("Select * from Msvm_ComputerSystem where Name = ElementName", virtService);
            if (results == null || results.isEmpty()) {
                // State is PROVISIONED
                throw new CollectorException(MessageValues.HYP_CONN_EXCP);
            }
            IJIDispatch dispatch = results.get(0);
            int rawState = dispatch.get("EnabledState").getObjectAsInt();
            HyperVState state = HyperVState.fromValue(rawState);
            if (state != HyperVState.POWER_ON) {
                // State is PROVISIONED
                throw new CollectorException(MessageValues.HYP_CONN_EXCP);
            }
        } catch (JIException ex) {
            throw new CollectorException(MessageValues.COLL_EXCP_DC, ex);
        } catch (UnknownHostException e) {
            throw new CollectorException(MessageValues.HYP_CONN_EXCP, e);
        } catch (MalformedURLException e) {
            throw new CollectorException(MessageValues.COLL_EXCP_DC, e);
        } catch (WsmanException e) {
            throw new NoManagedException(e.getMessage(), e);
        }
    }

    /**
     * Get the hypervisor version.
     * 
     * @return The hypervisor version.
     * @throws JIException If version cannot be retrieved.
     */
    private String getVersion() throws JIException {
        // Get Operating System object
        List<IJIDispatch> results = HyperVUtils.execQuery("Select * from Win32_OperatingSystem", cimService);
        IJIDispatch dispatch = results.get(0);
        // Find System directory and build Virtual Machine Management executable path
        String systemDirectory = dispatch.get("SystemDirectory").getObjectAsString2();
        String vmmsLoc = systemDirectory.replace("\\", "\\\\") + "\\\\vmms.exe";
        // Get Virtual Machine executable file data, to get version property
        results = HyperVUtils.execQuery("Select * from CIM_DataFile Where Name = '" + vmmsLoc + "'", cimService);
        dispatch = results.get(0);
        return dispatch.get("Version").getObjectAsString2();
    }

    /**
     * Gets the number of cores of the target node.
     * 
     * @return The number of cores of the target node.
     * @throws JIException If the number of cores cannot be retrieved.
     */
    private long getNumberOfCores() throws JIException {
        long numCores = 0;
        List<IJIDispatch> results = HyperVUtils.execQuery("Select * from Win32_Processor", cimService);
        for (IJIDispatch dispatch : results) {
            JIVariant numCoresRaw = dispatch.get("NumberOfCores");
            numCores += numCoresRaw.getObjectAsInt();
        }
        return numCores;
    }

    /**
     * Gets the virtual memory for the specified virtual system.
     * 
     * @param virtualSystemID The ID of the virtual system.
     * @return The amount of virtual memory available to the virtual system.
     * @throws JIException If virtual memory cannot be retrieved.
     */

    private long getVirtualMemory(final String virtualSystemID) throws JIException {
        List<IJIDispatch> results = HyperVUtils.execQuery("Select * from Msvm_MemorySettingData", virtService);
        for (IJIDispatch dispatch : results) {
            String instanceId = dispatch.get("InstanceID").getObjectAsString2();
            if (instanceId.startsWith("Microsoft:" + virtualSystemID)) {
                // Virtual quantity is stored in MB see AllocationUnits documentation at
                // http://msdn.microsoft.com/en-us/library/cc136856%28VS.85%29.aspx#properties
                String virtualQty = dispatch.get("VirtualQuantity").getObjectAsString2();
                return mbTobyte(Long.parseLong(virtualQty));
            }
        }
        LOGGER.warn("Could not get Virtual Memory for Virtual System: {}", virtualSystemID);
        return -1;
    }

    /**
     * Gets the number of the virtual processors for the specified virtual system.
     * 
     * @param virtualSystem The virtual system.
     * @return The number of virtual processors.
     * @throws JIException If the number of virtual processors cannot be retrieved.
     * @throws CollectorException If the number of virtual processors cannot be retrieved.
     */

    private long getVirtualProcessors(final IJIDispatch virtualSystem) throws JIException, CollectorException {
        // Get virtual machine settings
        String virtualSystemPath = HyperVUtils.getDispatchPath(virtualSystem);
        IJIDispatch settings = getVirtualSystemSettings(virtualSystemPath, virtService);
        try {
            MsvmVirtualSystemManagementService msManService = MsvmVirtualSystemManagementService
                    .getManagementService(virtService);
            MsvmVirtualSystemSettingData msSysSetData = new MsvmVirtualSystemSettingData(settings, virtService);
            MsvmSummaryInformation summ = msManService.getSummaryInformation(
                    new MsvmVirtualSystemSettingData[] { msSysSetData },
                    new Integer[] { HyperVConstants.NUMBER_OF_PROCESSORS_FIELD });
            return summ.getProperties().getItem("NumberOfProcessors").getValueAsLong();
        } catch (Exception ex) {
            throw new CollectorException(
                    "Could not get the number of processors of virtual system: " + virtualSystemPath, ex);
        }
    }

    /**
     * Gets the virtual disks attached to the virtual machine. TODO: get Bus information (controller
     * port) for attached Disks TODO: get bootOrder and setLabel(SYSTEM/OTHER)
     * 
     * @param virtualSystem The virtual machine.
     * @return The list of virtual disks.
     * @throws JIException If the list of virtual disks cannot be retrieved.
     * @throws CollectorException If disk information cannot be retrieved.
     */
    private List<ResourceType> getDisksInfo(final IJIDispatch virtualSystem)
            throws JIException, CollectorException {
        List<ResourceType> disks = new ArrayList<ResourceType>();
        String virtualSystemPath = HyperVUtils.getDispatchPath(virtualSystem);
        MsvmImageManagementService imageManagementService = MsvmImageManagementService
                .getManagementService(virtService);
        Map<String, List<IJIDispatch>> diskSettings = getDiskSettings(virtualSystemPath, virtService);

        // Getting info on standard VHD and volume disks as Msvm_ResourceAllocationSettingData
        // instances
        List<IJIDispatch> standardDiskSettings = diskSettings.get(STANDARD_DISKS_KEY);
        List<IJIDispatch> volumeDiskSettings = diskSettings.get(VOLUME_DISKS_KEY);

        // TODO: get Boot Order and establish which disk is the main one disk.setLabel(SYSTEM);
        // this could be done with Msvm_BIOSElement.BootOrder class and finding out the relations
        // with IDE/SCSI Controllers associated and their disks

        boolean firstDiskFound = true;

        for (IJIDispatch dispatch : standardDiskSettings) {

            // Get disk image path
            JIArray connection = dispatch.get("Connection").getObjectAsArray();
            JIVariant[] array = (JIVariant[]) connection.getArrayInstance();
            String imagePath = array[0].getObjectAsString2();
            imagePath = imagePath.replace("\\\\", "\\");
            ResourceType disk = new ResourceType();
            disk.setAddress(imagePath);

            disk.setConnection(getDatastoreFromFile(imagePath));

            disk.setResourceType(ResourceEnumType.HARD_DISK);

            // System Disk (1st bootable) is the 1st we find, until we get a solution for detecting BootOrder in HyperV machines  
            if (firstDiskFound) {
                disk.setLabel("SYSTEM DISK");
                firstDiskFound = false;
            } else {
                disk.setLabel("EXTRA DISK");
            }

            // TODO: we should also try to get bus number (IDE or SCSI used port associated)
            // disk.setAttachment({ControllerPort});

            try {
                // Must be one element disk.setImagePath(imagePath);
                // Get image size
                String info = imageManagementService.getVirtualHardDiskInfo(imagePath);

                LOGGER.info("getStandardDisks: " + info);

                String imageSize = XPathUtils.getValue("//PROPERTY[@NAME='FileSize']/VALUE", info);
                String typeString = XPathUtils.getValue("//PROPERTY[@NAME='Type']/VALUE", info);
                int type = Integer.parseInt(typeString);

                switch (type) {
                case 2:
                    disk.setResourceSubType(VirtualDiskEnumType.VHD_FLAT.value());
                    break;

                case 3:
                    disk.setResourceSubType(VirtualDiskEnumType.VHD_SPARSE.value());
                    break;

                case 4:
                    disk.setResourceSubType(VirtualDiskEnumType.INCOMPATIBLE.value());
                    break;

                default:
                    disk.setResourceSubType(VirtualDiskEnumType.UNKNOWN.value());
                    break;

                }
                disk.setUnits(Long.parseLong(imageSize));

            } catch (XPathExpressionException ex) {
                throw new CollectorException(
                        "Could not get virtual disk size of virtual system: " + virtualSystemPath);
            } catch (CollectorException ex) {
                // Just print
                LOGGER.error(
                        "Could not retrieve virtual disk info from virtual image path " + imagePath + ". Cause:",
                        ex);
                // This defaults values are set in case we are recovering disks that are shared in a
                // cluster shared value
                // TODO Maybe there is a way to get the disk info in a form of Cim_Datafile
                LOGGER.debug("Setting Default size and type values");
                disk.setResourceSubType(VirtualDiskEnumType.VHD_SPARSE.value());
                disk.setUnits(new Long(0));
            }

            disks.add(disk);
        }

        // INFO FOR VOLUME DISKS: we can get more info from Msvm_DiskDrive
        // Previously we collect all Win32_DiskDrive available
        Map<String, IJIDispatch> win32DiskDrives = getAllWin32DiskDrives();

        for (IJIDispatch dispatch : volumeDiskSettings) {

            ResourceType disk = new ResourceType();
            disk.setResourceType(ResourceEnumType.VOLUME_DISK);

            if (firstDiskFound) {
                disk.setLabel("SYSTEM DISK");
                firstDiskFound = false;
            } else {
                disk.setLabel("EXTRA DISK");
            }

            JIArray hostResource = dispatch.get("HostResource").getObjectAsArray();
            JIVariant[] array = (JIVariant[]) hostResource.getArrayInstance();
            String deviceID = array[0].getObjectAsString2();

            int diskDriveNumber = getDiskDriveNumberForDisk(deviceID);

            // Now we may get Win32_DiskDrive and find the Number

            // Parse \\.\PHYSICALDRIVE{DriveNumber} in Win32_DiskDrive collection
            IJIDispatch diskDriveDispatch = win32DiskDrives.get("\\\\.\\PHYSICALDRIVE" + diskDriveNumber);
            if (diskDriveDispatch != null) {
                long sizeinBytes = 0;
                try {
                    sizeinBytes = Long.parseLong(diskDriveDispatch.get("Size").getObjectAsString2());
                } catch (Exception sizeEx) {
                    LOGGER.error("Could not obtain size for diskDriveNumber " + diskDriveNumber, sizeEx);
                }
                disk.setUnits(sizeinBytes);
            }

            // TODO: we should also try to get bus number (IDE or SCSI used port associated)
            // disk.setAttachment({ControllerPort});

            disks.add(disk);
        }

        return disks;

    }

    /**
     * Looks for DiskDriveNumber in Msvm_DiskDrive class associated to
     * Msvm_ResourceAllocationSettingData (by DeviceID
     * 
     * @param deviceID
     * @return
     */
    private int getDiskDriveNumberForDisk(String deviceID) {
        int diskDriveNumber = -1;
        try {
            int deviceIDIndex = deviceID.indexOf("DeviceID=\"") + 10;
            String parsedDeviceID = deviceID.substring(deviceIDIndex, deviceID.indexOf("\"", deviceIDIndex));

            List<IJIDispatch> results = HyperVUtils.execQuery(
                    "Select * from Msvm_DiskDrive where DeviceID LIKE '%" + parsedDeviceID + "%'", virtService);
            IJIDispatch dispatch = results.get(0);

            diskDriveNumber = dispatch.get("DriveNumber").getObjectAsInt();

        } catch (Exception e) {
            LOGGER.error("Could not obtain DiskDrive Number (Msvm_DiskDrive) associated with this Virtual Machine",
                    e);
        }

        return diskDriveNumber;
    }

    /**
     * Get all Win32_DiskDrives objects mapped by DeviceID
     * 
     * @return
     */
    private Map<String, IJIDispatch> getAllWin32DiskDrives() {
        Map<String, IJIDispatch> result = new HashMap<String, IJIDispatch>();

        List<IJIDispatch> win32DiskDrives;
        try {
            win32DiskDrives = HyperVUtils.execQuery("Select * from Win32_DiskDrive", cimService);
            for (IJIDispatch resourceDispatch : win32DiskDrives) {
                result.put(resourceDispatch.get("DeviceID").getObjectAsString2(), resourceDispatch);
            }
        } catch (Exception ex) {
            LOGGER.error("Retrieving information on attached disks (Win32_DiskDrive) failed ", ex);
        }

        return result;
    }

    /**
     * Parses the fileName to get the datastore name
     * 
     * @param fileName the file name to parse
     * @return the datastore directory
     */
    private String getDatastoreFromFile(final String fileName) {
        int indexEndDirectory = fileName.lastIndexOf('\\');

        // If the images are copied in C:\ avoid to return 'C:' and put
        // the index in the next position
        if (indexEndDirectory == 2) {
            indexEndDirectory = 3;
        }

        return fileName.substring(0, indexEndDirectory);
    }

    /**
     * Gets the resource allocation settings for the specified Virtual System.
     * 
     * @param virtualSystemPath The virtual System.
     * @param service The service to use to run the queries.
     * @return The resource allocation settings.
     * @throws JIException If settings cannot be retrieved.
     * @throws CollectorException If settings cannot be retrieved.
     */
    private Map<String, List<IJIDispatch>> getDiskSettings(final String virtualSystemPath,
            final SWbemServices service) throws JIException, CollectorException {
        // Get virtual machine settings
        IJIDispatch settings = getVirtualSystemSettings(virtualSystemPath, virtService);
        String settingPath = HyperVUtils.getDispatchPath(settings);

        // Get virtual machine settings
        String settingsQuery = "Associators of {" + settingPath + "} Where "
                + "AssocClass = Msvm_VirtualSystemSettingDataComponent "
                + "ResultClass = Msvm_ResourceAllocationSettingData";
        List<IJIDispatch> results = HyperVUtils.execQuery(settingsQuery, service);

        List<IJIDispatch> standardDiskResults = new ArrayList<IJIDispatch>();
        List<IJIDispatch> volumeDiskResults = new ArrayList<IJIDispatch>();

        Map<String, List<IJIDispatch>> resultMap = new HashMap<String, List<IJIDispatch>>(2);

        for (IJIDispatch ijiDispatch : results) {
            if (HyperVUtils.isVolumeDisk(ijiDispatch)) {
                volumeDiskResults.add(ijiDispatch);
            }
            if (HyperVUtils.isVirtualHardDisk(ijiDispatch)) {
                standardDiskResults.add(ijiDispatch);
            }

        }
        resultMap.put(STANDARD_DISKS_KEY, standardDiskResults);
        resultMap.put(VOLUME_DISKS_KEY, volumeDiskResults);

        return resultMap;
    }

    /**
     * Gets the settings for the specified Virtual System.
     * 
     * @param virtualSystemPath The virtual System.
     * @param service The service to use to run the queries.
     * @return The virtual system settings.
     * @throws JIException If settings cannot be retrieved.
     * @throws CollectorException If settings cannot be retrieved.
     */

    private IJIDispatch getVirtualSystemSettings(final String virtualSystemPath, final SWbemServices service)
            throws JIException, CollectorException {
        // Get virtual machine settings
        String settingsQuery = "Associators of {" + virtualSystemPath + "} Where "
                + "AssocClass = Msvm_SettingsDefineState " + "ResultClass = Msvm_VirtualSystemSettingData";

        List<IJIDispatch> results = HyperVUtils.execQuery(settingsQuery, service);
        if (results == null || results.isEmpty()) {
            throw new CollectorException(
                    "Could not get Virtual System settings of virtual system: " + virtualSystemPath);
        }
        return results.get(0);
    }

    /**
     * Converts MB to bytes.
     * 
     * @param mbytes The MB to convert.
     * @return The converted result.
     */

    private static long mbTobyte(final long mbytes) {
        final int MB_TO_BYTE = 1048576;
        return mbytes * MB_TO_BYTE;
    }

    /**
     * Retrieves the list of resources of the host.
     * 
     * @throws CollectorException for collector exceptions.
     * @throws JIException thrown by any JI* object.
     * @return the list of ResourceType objects.
     */
    private List<ResourceType> getHostResources() throws JIException, CollectorException {
        // Returning vswitch list
        List<ResourceType> resources = new ArrayList<ResourceType>();
        resources.addAll(filterNetworkList());
        resources.addAll(getDatastoresAsWin32LogicalDisk());
        resources.addAll(getMappedLogicalDisks());

        return resources;
    }

    /**
     * Private helper to filter the network list (vSwitch) list.
     * 
     * @return the resource list
     * @throws JIException thrown by any JI* Object.
     */
    private List<ResourceType> filterNetworkList() throws JIException {
        final List<IJIDispatch> resultsVswitchs = HyperVUtils.execQuery("Select * from Msvm_VirtualSwitch",
                virtService);
        String macs = getMacs();
        List<ResourceType> filteredNetworks = new ArrayList<ResourceType>();
        for (IJIDispatch networkDispatch : resultsVswitchs) {
            String networkName = networkDispatch.get("ElementName").getObjectAsString2();
            ResourceType resource = new ResourceType();
            resource.setAddress(macs);
            resource.setElementName(networkName);
            resource.setResourceType(ResourceEnumType.NETWORK_INTERFACE);
            filteredNetworks.add(resource);

        }

        Collections.sort(filteredNetworks, new ResourceComparator());

        return filteredNetworks;
    }

    /**
     * Retrieve the mac and add them as a resources. Ignore interfaces with no address. If no macs
     * then return an empty String. Don't care about except. Just append mac \ mac \ ...
     * 
     * @param networks all win32 interfaces.
     * @return all interfaces as a physical resources. mac1\mac2\...
     */
    private String getMacs() {
        List<IJIDispatch> networks;
        StringBuilder macs = new StringBuilder("");
        try {
            networks = HyperVUtils.execQuery("Select * from Win32_NetworkAdapter", cimService);
            for (IJIDispatch resourceDispatch : networks) {
                try {
                    String rawMac = resourceDispatch.get("MACAddress").getObjectAsString2();
                    if (StringUtils.isBlank(rawMac)) {
                        continue;
                    }
                    macs.append(rawMac).append("\\");
                } catch (Exception ex) {
                    LOGGER.debug("This interface has no mac");
                }
            }
        } catch (Exception ex) {
            LOGGER.debug("There are no interface with mac");
        }
        return macs.length() > 1 ? macs.substring(0, macs.length() - 1) : macs.toString();

    }

    /**
     * Gets All datastores enabled in Hyper-V machine as mapped network drives
     * 
     * @return The Win32_LogicalDisk list
     * @throws JIException If disk size cannot be retrieved.
     * @throws CollectorException If Physical drive cannot be retrieved.
     */
    private List<ResourceType> getDatastoresAsWin32LogicalDisk() throws JIException, CollectorException {
        List<IJIDispatch> results = HyperVUtils.execQuery("Select * from Win32_LogicalDisk", cimService);

        if (results == null || results.isEmpty()) {
            throw new CollectorException("Could not get physical drive for virtual machine disks");
        }

        List<ResourceType> disksResources = new ArrayList<ResourceType>();
        for (IJIDispatch logicalDiskDispatch : results) {
            int driveType = logicalDiskDispatch.get("DriveType").getObjectAsInt();
            // Ignoring removable disks (2), compact disks(5) and mappedlogicaldrives(4)
            if (driveType == 2 || driveType == 5 || driveType == 4) {
                continue;
            }
            String logicalDiskName = logicalDiskDispatch.get("DeviceID").getObjectAsString2();
            String size = logicalDiskDispatch.get("Size").getObjectAsString2();
            String availableSize = logicalDiskDispatch.get("FreeSpace").getObjectAsString2();
            // String datastoreUuidMark = getDatastoreUuidMark(logicalDiskName);

            ResourceType resource = new ResourceType();
            resource.setAddress(logicalDiskName + "\\");
            resource.setElementName(logicalDiskName);
            resource.setResourceType(ResourceEnumType.HARD_DISK);
            resource.setUnits(Long.valueOf(size));
            resource.setAvailableUnits(Long.valueOf(availableSize));
            // resource.setConnection(datastoreUuidMark);
            disksResources.add(resource);

        }

        Collections.sort(disksResources, new ResourceComparator());

        return disksResources;
    }

    /**
     * Gets Mapped network drives in Windows machines: these are the only candidates to be
     * considered as shared datastores by Abiquo Datastores must be created in Win32 host machines
     * NOT associated with any user session.
     * 
     * @return
     * @throws JIException
     * @throws CollectorException
     */
    private List<ResourceType> getMappedLogicalDisks() throws JIException, CollectorException {
        List<IJIDispatch> results = HyperVUtils.execQuery("Select * from Win32_MappedLogicalDisk", cimService);

        // This query can return repeated Win32_MappedLogicalDisk instances, we should remove them
        // This is caused by Disks being associated to more than one SessionId
        List<String> deviceIds = new ArrayList<String>();

        List<ResourceType> disksResources = new ArrayList<ResourceType>();
        for (IJIDispatch logicalDiskDispatch : results) {
            String logicalDiskName = logicalDiskDispatch.get("DeviceID").getObjectAsString2();
            if (!deviceIds.contains(logicalDiskName)) { // Repeated Win32_MappedLogicalDisk instances are not included
                String size = logicalDiskDispatch.get("Size").getObjectAsString2();
                String availableSize = logicalDiskDispatch.get("FreeSpace").getObjectAsString2();
                String datastoreUuidMark = getDatastoreUuidMark(logicalDiskName);

                ResourceType resource = new ResourceType();
                resource.setAddress(logicalDiskName + "\\");
                resource.setElementName(logicalDiskName);
                resource.setResourceType(ResourceEnumType.HARD_DISK);
                resource.setUnits(Long.valueOf(size));
                resource.setAvailableUnits(Long.valueOf(availableSize));
                resource.setConnection(datastoreUuidMark);
                disksResources.add(resource);

                deviceIds.add(logicalDiskName);
            }

        }

        Collections.sort(disksResources, new ResourceComparator());

        return disksResources;
    }

    /**
     * Gets the iSCSI Initiator IQN of the host.
     * 
     * @param hostName The name of the host
     * @return The iSCSI Initiator IQN of the host.
     * @throws Exception if an error occurs.
     */
    private String getInitiatorIQN(final String hostName) throws Exception {
        String iqn = null;

        // First check if the IQN has been set manually.
        registry.connect(getIpAddress(), hyperVuser, hyperVpassword);

        try {
            iqn = registry.getKeyValue(WindowsRegistry.Keys.HKEY_LOCAL_MACHINE,
                    HyperVConstants.INITIATOR_REGISTRY_PATH, HyperVConstants.INITIATOR_REGISTRY_KEY);
        } finally {
            registry.disconnect();
        }

        // If the key was not found, then use the default IQN
        if (iqn == null) {
            iqn = HyperVConstants.DEFAULT_INITIATOR_NAME_PREFIX + hostName.toLowerCase();
        }

        return iqn;
    }

    /**
     * Locate or create the datastore folder mark to determine if the datastore is being shared
     * across hypervisors.
     * 
     * @return a Datastore UUID
     * @throws CollectorException
     */
    private String getDatastoreUuidMark(final String mappedDrive) // , HostDatastoreBrowser
            // dsBrowser,
            // Datacenter dc)
            throws CollectorException {
        String dsUUID = null;

        // Preparing the query
        String query = "SELECT * FROM CIM_DataFile WHERE FileName LIKE '" + DATASTORE_UUID_MARK + "%' AND Drive = '"
                + mappedDrive + "'";

        JIVariant[] res;
        try {
            res = cimService.getObjectDispatcher().callMethodA("ExecQuery", new Object[] { new JIString(query) });
            JIVariant[][] fileSet = HyperVUtils.enumToJIVariantArray(res);
            if (fileSet.length == 1) {
                IJIDispatch fileDispatch = (IJIDispatch) JIObjectFactory
                        .narrowObject(fileSet[0][0].getObjectAsComObject().queryInterface(IJIDispatch.IID));
                dsUUID = fileDispatch.get("FileName").getObjectAsString2();
                // throw new Exception("Cannot identify the vhd to delete: " + file);
            } else if (fileSet.length > 1) {
                throw new CollectorException(MessageValues.DATASTRORE_MULTIPLE_MARKS);
            }
        } catch (JIException e) {
            LOGGER.error("Can not locate the folder mark at [{}]\n{}", e);
            throw new CollectorException(MessageValues.DATASTRORE_MARK, e);
        }

        if (dsUUID == null) {
            dsUUID = createDatastoreFolderMark(mappedDrive);
        }
        return dsUUID;
    }

    private String createDatastoreFolderMark(final String mappedDrive) throws CollectorException {
        String folderUuidMark = UUID.randomUUID().toString();
        String directoryOnDatastore = String.format("%s\\%s%s", mappedDrive, DATASTORE_UUID_MARK, folderUuidMark);
        // Should be something like Z:\\abq.datastoreuuid.343423429

        try {

            IJIDispatch instanceClass = (IJIDispatch) JIObjectFactory.narrowObject(cimService.getObjectDispatcher()
                    .callMethodA("Get", new Object[] { new JIString("Win32_Process") })[0].getObjectAsComObject()
                            .queryInterface(IJIDispatch.IID));
            // Win32_Process do not need to be instanced (SpawnInstance_)

            Win32Process proc = new Win32Process(instanceClass, cimService);
            // proc.create("cmd.exe /C mkdir " + folder);

            proc.create("cmd.exe /C echo emptydata > " + directoryOnDatastore);

            // do not create parent folders (is on the root)
            // serviceInstance.getFileManager().makeDirectory(directoryOnDatastore, dc, false);
        } catch (Exception e) {
            LOGGER.error("Can not create the folder mark at [{}]\n{}", mappedDrive, e);
            throw new CollectorException(MessageValues.DATASTRORE_MARK, e);
        }

        return folderUuidMark;
    }

}