/**
* 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;
}
}