// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved namespace Microsoft.Samples.HyperV.FibreChannel { using System; using System.Collections.Generic; using System.Management; using System.Globalization; using Microsoft.Samples.HyperV.Common; /// /// Represents a WWPN WWNN Tuple, to identify an FC Port. /// internal struct WorldWideName { public string PortName; public string NodeName; }; static class FibreChannelUtilities { internal static readonly string FcConnectionResourceType = "64764"; //0xFCFC internal static readonly string FcConnectionResourceSubType = "Microsoft:Hyper-V:FibreChannel Connection"; internal static readonly string FcDeviceName = "Fibre Channel Adapter"; /// /// Get the ManagementScope to connect to Hyper-V WMI. /// /// ManagementScope to connect to Hyper-V WMI. internal static ManagementScope GetFcScope() { return new ManagementScope(@"root\virtualization\v2"); } /// /// Follows the associations from the resource pool to get the default object for the /// resource type exposed by this resource pool. /// /// The resource pool. /// The scope to use when connecting to WMI. /// /// The default settings for the resource type managed by this resource pool. /// internal static ManagementObject GetDefaultObjectFromResourcePool( ManagementObject resourcePool, ManagementScope scope) { // // The default object is associated with the Msvm_AllocationCapabilities object that // is associated to the resource pool. // string defaultSettingPath = null; using (ManagementObjectCollection capabilitiesCollection = resourcePool.GetRelated("Msvm_AllocationCapabilities", "Msvm_ElementCapabilities", null, null, null, null, false, null)) using (ManagementObject capabilities = WmiUtilities.GetFirstObjectFromCollection(capabilitiesCollection)) { foreach (ManagementObject settingAssociation in capabilities.GetRelationships("Msvm_SettingsDefineCapabilities")) { using (settingAssociation) { if ((ushort)settingAssociation["ValueRole"] == 0) { defaultSettingPath = (string)settingAssociation["PartComponent"]; break; } } } } if (defaultSettingPath == null) { throw new ManagementException(string.Format(CultureInfo.CurrentCulture, "Unable to find the default settings!")); } ManagementObject defaultSetting = new ManagementObject(defaultSettingPath); defaultSetting.Scope = scope; defaultSetting.Get(); return defaultSetting; } /// /// Gets the default connection settings object to use when adding new connection settings. /// /// The scope to use when connecting to WMI. /// The name of the San / pool ID of the Resource Pool. /// The default connection object. internal static ManagementObject GetDefaultFcPortAllocationSettingData( ManagementScope scope, string sanName) { // // First get the resource pool for FC connection objects. // ObjectQuery query = new ObjectQuery(string.Format(CultureInfo.InvariantCulture, "SELECT * FROM Msvm_ResourcePool WHERE ResourceType = {0} AND PoolID = '{1}'", FcConnectionResourceType, sanName)); using (ManagementObjectSearcher queryExecute = new ManagementObjectSearcher(scope, query)) using (ManagementObject resourcePool = WmiUtilities.GetFirstObjectFromCollection(queryExecute.Get())) { return GetDefaultObjectFromResourcePool(resourcePool, scope); } } /// /// Uses the WWPN Generator and the Configures WWNN to generate the 2 sets /// of WWNs for a Virtual FC Adapter. /// /// ManagementScope for WMI connection. /// On success will have the virtual WWN for the Virtual HBA. /// On success will have the secondary WWN for the Virtual HBA. internal static void GenerateWorldWideNames( ManagementScope scope, ref WorldWideName wwnA, ref WorldWideName wwnB) { using (ManagementObject settings = WmiUtilities.GetVirtualMachineManagementServiceSettings(scope)) using (ManagementObject managementService = WmiUtilities.GetVirtualMachineManagementService(scope)) using (ManagementBaseObject inParams = managementService.GetMethodParameters("GenerateWwpn")) { // Set WWNN. string assignedWwnn = settings["CurrentWWNNAddress"].ToString(); wwnA.NodeName = assignedWwnn; wwnB.NodeName = assignedWwnn; // Generate 2 WWPNs for the 2 sets. inParams["NumberOfWwpns"] = 2; using (ManagementBaseObject outParams = managementService.InvokeMethod("GenerateWwpn", inParams, null)) { WmiUtilities.ValidateOutput(outParams, scope); // Requested for 2 WWPNs to be generated. string[] wwpnArray = outParams["GeneratedWwpn"] as string[]; wwnA.PortName = wwpnArray[0]; wwnB.PortName = wwpnArray[1]; } } } /// /// For a valid ExternalFcPort, get the host resource to be added to a virtual SAN. /// /// The WWN for the ExternalFcPort. /// /// WMI Path to the VirtualFcSwitch instance for the ExternalFcPort, /// which is the host resource for the virtual SAN. /// internal static string GetHostResourceFromWwn( WorldWideName wwn ) { ManagementScope scope = GetFcScope(); // // If the wwn is for a valid ExternalFcPort, we should be able to get // the FcEndpoint for the VirtualFcSwitch for the ExternalFcPort. // For every valid ExternalFcPort, there is guaranteed to be a corresponding // unique VirtualFcSwitch. // string queryString = string.Format(CultureInfo.InvariantCulture, "SELECT * FROM Msvm_FcEndpoint WHERE SystemCreationClassName = '{0}'" + " AND WWNN = '{1}' AND WWPN = '{2}'", "Msvm_VirtualFcSwitch", wwn.NodeName, wwn.PortName); ObjectQuery query = new ObjectQuery(queryString); using (ManagementObjectSearcher switchEndpointSearcher = new ManagementObjectSearcher(scope, query)) using (ManagementObject switchEndpoint = WmiUtilities.GetFirstObjectFromCollection(switchEndpointSearcher.Get())) { string switchQueryString = string.Format(CultureInfo.InvariantCulture, "SELECT * FROM Msvm_VirtualFcSwitch WHERE Name = '{0}'", switchEndpoint["SystemName"]); ObjectQuery switchQuery = new ObjectQuery(switchQueryString); using (ManagementObjectSearcher switchSearcher = new ManagementObjectSearcher(scope, switchQuery)) using (ManagementObjectCollection fcSwitches = switchSearcher.Get()) // // There is only 1 VirtualFcSwitch for an ExternalFcPort. // using (ManagementObject fcSwitch = WmiUtilities.GetFirstObjectFromCollection(fcSwitches)) { return fcSwitch.Path.Path; } } } /// /// Returns the Msvm_ResourcePoolConfigurationService instance. /// /// The ManagementScope to use to connect to WMI. /// The resource pool configuration service instance. internal static ManagementObject GetResourcePoolConfigurationService( ManagementScope scope) { using (ManagementClass resourcePoolConfigurationServiceClass = new ManagementClass("Msvm_ResourcePoolConfigurationService")) { resourcePoolConfigurationServiceClass.Scope = scope; // // Msvm_ResourcePoolConfigurationService is a singleton object. // ManagementObject resourcePoolConfigurationService = WmiUtilities.GetFirstObjectFromCollection( resourcePoolConfigurationServiceClass.GetInstances()); return resourcePoolConfigurationService; } } /// /// Returns an embedded instance string of an Msvm_ResourcePoolSettingData /// object, initialized with the specified pool ID, pool name, notes, and resource /// information. /// /// The ManagementScope to use to connect to WMI. /// The pool ID to assign. /// The Notes for the Virtual SAN to assign. /// /// The embedded instance string of an Msvm_ResourcePoolSettingData object. internal static string GetSettingsForPool( ManagementScope scope, string poolId, string notes ) { using (ManagementClass rpsdClass = new ManagementClass("Msvm_ResourcePoolSettingData")) { rpsdClass.Scope = scope; using (ManagementObject rpsdInstance = rpsdClass.CreateInstance()) { rpsdInstance["ResourceType"] = FcConnectionResourceType; rpsdInstance["ResourceSubType"] = FcConnectionResourceSubType; rpsdInstance["OtherResourceType"] = string.Empty; rpsdInstance["PoolId"] = poolId; if (notes != null) { rpsdInstance["Notes"] = notes; } rpsdInstance["ElementName"] = @"Friendly name for virtual SAN - " + poolId; string rpsdString = rpsdInstance.GetText(TextFormat.WmiDtd20); return rpsdString; } } } /// /// Returns an embedded instance string of a Msvm_ResourceAllocationSettingData /// object initialized with the specified pool ID, and resource information. /// /// The ManagementScope to use to connect to WMI. /// The pool ID to assign. /// An array of strings that indicates the /// host resources to assign to the pool. /// /// The embedded instance string of a Msvm_ResourceAllocationSettingData object. /// internal static string GetNewPoolAllocationSettings( ManagementScope scope, string poolId, string[] hostResources ) { using (ManagementClass rasdClass = new ManagementClass("Msvm_ResourceAllocationSettingData")) { rasdClass.Scope = scope; using (ManagementObject rasdInstance = rasdClass.CreateInstance()) { rasdInstance["ResourceType"] = FcConnectionResourceType; rasdInstance["ResourceSubType"] = FcConnectionResourceSubType; rasdInstance["OtherResourceType"] = string.Empty; rasdInstance["PoolId"] = poolId; rasdInstance["HostResource"] = hostResources; string rasdString = rasdInstance.GetText(TextFormat.WmiDtd20); return rasdString; } } } /// /// Gets the WMI Path to the FC Connection Resource Pool. /// /// The ManagementScope used to connecto to WMI. /// PoolId of the ResourcePool (or SAN Name). /// Should be null or empty for the primordial pool. /// The WMI Path to the Primordial FC Connection Pool. internal static string GetResourcePoolPath( ManagementScope scope, string poolId ) { string poolQuery = "SELECT * FROM Msvm_ResourcePool WHERE ResourceType = " + FcConnectionResourceType; if (poolId == null || poolId.Length == 0) { poolQuery += " AND Primordial = TRUE"; } else { poolQuery += " AND PoolId = '" + poolId + "'"; } ObjectQuery query = new ObjectQuery(poolQuery); using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query)) using (ManagementObjectCollection pools = searcher.Get()) { return WmiUtilities.GetFirstObjectFromCollection(pools).Path.Path; } } } }