/// <summary> /// Extracts information about a brokerlauncher resource group /// </summary> /// <param name="hCluster">Failover cluster connection</param> /// <param name="resourceGroupName">Name of the response group</param> /// <returns>Resource group availability and network name</returns> static public ResourceGroupInfo Get(IntPtr hCluster, string resourceGroupName) { IntPtr hGroup = IntPtr.Zero; IntPtr hResourceGroupEnum = IntPtr.Zero; IntPtr hResource = IntPtr.Zero; ResourceGroupInfo resourceGroupInfo = null; int resourceGroupNetworkNameLen = Win32API.MAX_HOST_NAME_LEN; StringBuilder resourceGroupNetworkName = new StringBuilder(resourceGroupNetworkNameLen); bool resourceGroupAvailable = false; int nameLen = Win32API.MAX_HOST_NAME_LEN; StringBuilder name = new StringBuilder(nameLen); int hostNameLen = Win32API.MAX_HOST_NAME_LEN; StringBuilder hostName = new StringBuilder(hostNameLen); try { // Open the resource group hGroup = Win32API.OpenClusterGroup(hCluster, resourceGroupName); if (hGroup == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error(), string.Format(SR.ResourceGroupInfo_CannotOpenResourceGroup, name)); } // Get group's state and save whether its available CLUSTER_GROUP_STATE groupState = Win32API.GetClusterGroupState(hGroup, hostName, ref hostNameLen); resourceGroupAvailable = IsGroupAvailable(groupState); // If the resource group isnt available, move on to the next one if (!resourceGroupAvailable) { return(null); } // Enumerate resources within the resource group hResourceGroupEnum = Win32API.ClusterGroupOpenEnum(hGroup, (int)CLUSTER_GROUP_ENUM.CLUSTER_GROUP_ENUM_ALL); if (hResourceGroupEnum == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error(), SR.ResourceGroupInfo_CannotEnumerateResourceGroup); } int index = 0; int type = 0; bool exit = false; int enumResult = (int)CLUSTER_ENUM_RESULT.ERROR_SUCCESS; IntPtr loginToken = IntPtr.Zero; nameLen = Win32API.MAX_HOST_NAME_LEN; // Enumerate through the resources to get network name while (!exit) { name = new StringBuilder(nameLen); // If previous iteration opened a resource, close it before opening another if (hResource != IntPtr.Zero) { Win32API.CloseClusterResource(hResource); hResource = IntPtr.Zero; } enumResult = Win32API.ClusterGroupEnum(hResourceGroupEnum, index, out type, name, ref nameLen); if (enumResult == (int)CLUSTER_ENUM_RESULT.ERROR_SUCCESS) { // Debug.Assert(type == (int)CLUSTER_GROUP_ENUM.CLUSTER_GROUP_ENUM_CONTAINS); if (type == (int)CLUSTER_GROUP_ENUM.CLUSTER_GROUP_ENUM_CONTAINS) { hResource = Win32API.OpenClusterResource(hCluster, name.ToString()); if (hResourceGroupEnum == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error(), String.Format(SR.ResourceGroupInfo_CannotOpenResource, name)); } // Check if the resource type is a Generic Application. If not continue to the next if (!Win32API.ResUtilResourceTypesEqual("Generic Application", hResource)) { nameLen = Win32API.MAX_HOST_NAME_LEN; index++; continue; } // TODO: Consider checking generic application's command line to see if its brokerlauncher if ( !Win32API.GetClusterResourceNetworkName(hResource, resourceGroupNetworkName, ref resourceGroupNetworkNameLen)) { int errorCode = Marshal.GetLastWin32Error(); if (errorCode != (int)WIN32_ERRORS.ERROR_DEPENDENCY_NOT_FOUND) { throw new Win32Exception(errorCode, string.Format(SR.ResourceGroupInfo_CannotGetNetworkName, resourceGroupName)); } } exit = true; } else { nameLen = Win32API.MAX_HOST_NAME_LEN; index++; continue; } } else if (enumResult == (int)CLUSTER_ENUM_RESULT.ERROR_NO_MORE_ITEMS) { exit = true; } else if (enumResult == (int)CLUSTER_ENUM_RESULT.ERROR_MORE_DATA) { // try same item again with returned nameLen continue; } else { throw new Exception(String.Format(SR.UnexpectedReturnValue, enumResult)); } } if (resourceGroupNetworkName.Length != 0) { resourceGroupInfo = new ResourceGroupInfo(resourceGroupNetworkName.ToString(), resourceGroupAvailable, hostName.ToString()); } return(resourceGroupInfo); } finally { if (hResource != IntPtr.Zero) { Win32API.CloseClusterResource(hResource); } if (hResourceGroupEnum != IntPtr.Zero) { Win32API.ClusterResourceCloseEnum(hResourceGroupEnum); } if (hGroup != IntPtr.Zero) { Win32API.CloseClusterGroup(hGroup); } } }
/// <summary> /// Get broker's identity. If on a failover cluster, get resoruce group network name /// computer account login token /// Notice: This method returns null if it is not failover cluster or it is Azure cluster. /// </summary> /// <returns></returns> private static WindowsIdentity GetBrokerIdentity() { if (SoaHelper.IsOnAzure()) { // Skip following logic if it is on Azure. return(null); } int clusterState = (int)ClusterState.ClusterStateNotInstalled; uint ret = Win32API.GetNodeClusterState(null, out clusterState); if (ret != 0) { TraceHelper.TraceEvent(TraceEventType.Error, "Cannot access local failover cluster state. Error = {0}", ret); return(null); } if (clusterState == (int)ClusterState.ClusterStateNotConfigured || clusterState == (int)ClusterState.ClusterStateNotInstalled) { TraceHelper.TraceEvent(TraceEventType.Information, "Cannot access local failover cluster state. Error = {0}", ret); return(null); } IntPtr hCluster = IntPtr.Zero; IntPtr hResource = IntPtr.Zero; try { // Get handle to local failover cluster hCluster = Win32API.OpenCluster(null); if (hCluster == IntPtr.Zero) { TraceHelper.TraceEvent(TraceEventType.Error, "Cannot connect to local failover cluster. Error = {0}", Marshal.GetLastWin32Error()); return(null); } // Get handle to this broker's network name resource hResource = Win32API.OpenClusterResource(hCluster, Environment.MachineName); if (hResource == IntPtr.Zero) { TraceHelper.TraceEvent(TraceEventType.Error, "Cannot connect to local failover cluster. Error = {0}", Marshal.GetLastWin32Error()); return(null); } // Get the login token of the network name for the broker's resource group's network name. This // is a computer account login token and is use to impersonate all calls to the services. The services // then ensure calls are only from broker nodes or resource groups. IntPtr loginToken = IntPtr.Zero; try { loginToken = GetNetworkNameLoginToken(hCluster, hResource); if (loginToken != IntPtr.Zero) { // Put login token in a WindowsIdentity object // WindowsIdentity calls DuplicateToken and it is fine to close the handle later return(new WindowsIdentity(loginToken)); } else { return(null); } } finally { if (loginToken != IntPtr.Zero) { Win32API.CloseHandle(loginToken); } } } finally { if (hResource != IntPtr.Zero) { Win32API.CloseClusterResource(hResource); } if (hCluster != IntPtr.Zero) { Win32API.CloseCluster(hCluster); } } }