两个、三个、多个计算群集:在 Active Directory 中查找群集

发布者 Microsoft 脚本专家

英语是一种奇妙的语言。条条大路通罗马,您可以说要剥猫皮的方法不止一种(可千万不要对着脚本专家的猫这么说:他们将拿你开刀)。 ** ** ** 那么,配置计算群集的方式也有很多种。计算群集配置数不胜数,可以说计算群集配置比你挥动球棒的办法还多(不要对某些热爱棒球的脚本专家这样说:他会告诉你挥动球棒的时候,应该保持后肘朝上运行)。您可能还认为太多的系统管理员破坏了计算群集,但是这种说法反过来的话可能会更正确:系统管理员是越多越好。看到了吧,不要责怪脚本专家:不是我们创造了这种诡辩的语言;只是我们没有正确使用而已(本文章还包含指向英文网页的链接)。

无论您使用什么样的谚语来形容,计算群集都必定会呈现出各种各样的形状和大小。某些组织可能会将计算群集扩展为并行模式,使之具有等同超级计算机的海量计算能力,其配备的数百个节点能够满足组织内部所有人员的繁重计算任务。另一方面,组织的其他部门或办公室桌面可能会需要更小巧的电脑。在后面这种情形中,可能要在相同的网络段和 Active Directory 域中部署许多小型计算群集。如果这与您作为计算群集管理员的工作不谋而合,我们希望本文和脚本合您的胃口,成为您的掌中宝,心头肉,(哈哈,大家都这么说,顺口啊)。

Scripto 博士:人人都有鸡吃,人人都用计算群集。

本页内容

推荐使用 ADO
Cscript 与否?
脚本的内容是什么?
收集群集
资源

推荐使用 ADO

您在 Windows Server 2003 上安装 Compute Cluster Server (CCS) 时,除操作系统外,还需要插入其他许多结构。除此之外,CCS 还可与 Active Directory 集成以进行域和身份管理。

要使用脚本和应用程序在计算群集中处理最多的用户和组授权与验证工作,可以使用主要的 Active Directory Windows 脚本库 - Active Directory Service Interfaces (ADSI)。

但是您可能不知道,还有另外的脚本库能有助于实现目录管理自动化。这就是 ActiveX 数据对象 (ADO),第一款并且是最重要的数据库脚本和编程技术。可以为文本文件、电子表格、以及多种数据库等众多数据源提供一致的编程接口。鉴于目录也是一种数据库,ADO 可成为 Active Directory 脚本编写者和编程人员的灵活的工具。此时,对我们来说 ADO 比 ADSI 具有特殊优势:ADO 通常是在多级目录容器中往复搜索资源的最佳方式。

在目前情况下,我们有意要搜索特殊种类的资源:计算群集。如果您不得不在上述环境中管理多个群集,则 ADO 可能是对脚本的有益补充,有助于管理这些分布式群集中的用户、组和计算机。

Cscript 与否?

在查看脚本代码之前,需要确定脚本运行环境已做好准备。对于大多数脚本而言,您必须拥有运行该脚本计算机的管理权限。

在此情况下,拥有域用户凭据的所有人都能够看到域中的计算群集;同时,拥有作为群集用户权限的所有人都能够从群集及其节点中检索状态信息。但是,与所有 Windows 脚本一样,运行脚本的凭据不允许脚本在图形用户界面中或使用其他命令行工具执行这些凭据无法执行的任何操作。

如果尚未从运行该脚本的工作站或者头节点中运行管理脚本,则请务必保证 Windows Script Host 的默认脚本宿主设置为 Cscript.exe 命令行宿主,而不是 Wscript.exe 图形用户界面宿主(除非您喜欢重复单击“确定”)。

要将 Cscript.exe 设为默认值,请在命令提示符下键入:

cscript //h:cscript //nologo //s

//h 交换机设置默认脚本宿主;//nologo 交换机防止每次运行脚本时都运行多行无关的词语;//s 交换机将这些设置另存为默认设置。

脚本的内容是什么?

让我们来讨论一下实质问题,或者具体细节,或者任何您想要认真考虑的事情。该脚本跟踪 Active Directory 容器中的所有计算群集,并检查所有群集及其节点的功能和状态。采用两项主要的脚本技术:ADO,用于查找指定 Active Directory 容器中的计算群集;以及 Compute Cluster Pack (CCP) scripting API,用于返回关于群集和节点的信息。该脚本还充分利用一些内置的 VBScript 功能,以进行字符串分析和错误处理。

由于大多数较长的脚本都位于Scripting for Compute Cluster Server(英文),则此脚本开始的部分将定义常量和变量。在运行该脚本之前,必须将分配到 strContainer 的值更改为您的 Active Directory 结构中的实际容器。

Const ADS_SCOPE_SUBTREE = 2
strContainer = "CN=computers,DC=fabrikam,DC=com" 'Accessible AD container.
strObjectCategory = "ServiceConnectionPoint" 'For CCS
strServiceClassName = "MicrosoftComputeCluster"

下面的约 20 行内容用于设置 ADO 基础结构,以便执行 ADO 容器搜索。该部分大多数都是样板化的,能够与多数的 Active Directory ADO 查询配合使用。首先创建两个对象引用:一个是 Connection 对象,告诉 ADO 您想连接到何种类型的数据提供程序;另一个是 Command 对象,用于定义您想要运行的查询,希望运行与之相对应的容器,以及查询应该返回何种类型的数据集。

Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")

一旦指派提供程序并打开 Connection 对象,则将 Connection 对象指派给命令的 ActiveConnection 属性:

objConnection.Provider = ("ADsDSOObject")
objConnection.Open "Active Directory Provider"
objCommand.ActiveConnection = objConnection

然后在 Command 对象上开始工作。如果想要检索您正在搜索的所有信息,则需要设置页面大小。(关于页面大小的详细信息,请参阅 Scripting Puzzle(英文))。常量 ADS_SCOPE_SUBTREE 代表整数 2,被指派给 Searchscope 属性,通过指定的容器和所有子容器告诉 ADO 进行往复搜索。“cn”属性(针对“公用名称”)被指派给 Sort On 属性,以要求 ADO 按照计算群集的名称对数据进行排序。

objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
objCommand.Properties("Sort On") = "cn"

本部分最复杂的代码用于定义查询,并将其指派给 Command 对象的 CommandText 属性。借助 ADO,可以使用 SQL 或 LDAP 语法来查询目录。此处我们使用 SQL:

objCommand.CommandText = _ 
 "SELECT serviceClassName,servicednsname FROM 'LDAP://" & _
 strContainer & "' " & _
 "WHERE objectCategory = '" & strObjectCategory & "' " & _
 "AND serviceClassName = '" & strServiceClassName & "'"

该查询检索容器的两个属性:serviceClassName 和 servicednsname,由 WHERE 子句进行筛选。该子句表示,查询仅需要那些符合两个标准的对象:其类别必须是 ServiceConnectionPoint,其 serviceClassName 必须是 MicrosoftComputeCluster。根据 Active Directory 架构,符合这些标准的对象最好是计算群集。

借助专为计算群集加载的 Command 对象,脚本通过调用 Execute 方法触动触发器。这种方法会根据容器运行查询。之后,Execute 将所有结果加入到相应对象之中,该对象为一组符合查询标准的记录。我们将该对象的引用指派给名为 objRecordSet 的变量。谁说变量命名方法不是一门艺术?

Set objRecordSet = objCommand.Execute

在此关键时刻,借助刚获取的记录集,可以利用scriptus interruptus 来检查在使用 VBScript 内置 Err 对象时的错误(在脚本开始时与 On Error Resume Next 语句协同工作)。如果 Execute 命令失败将会如何?这通常意味着无法访问容器,因此脚本调用 HandleError 函数并为其传递适当信息,然后显示 VBScript 错误信息。然后查询并返回,因为没有设置继续进行的记录。

On Error Resume Next
...
If Err Then
  HandleError "ERROR: Unable to find container: " & strContainer
  WScript.Quit
End If

如果命令未返回错误,则脚本显示如下消息:正在搜索容器并向前插入记录集。现在,如果只是想了解此处计算群集的名称,则仅需遍历记录集来获取这些名称即可。但是在此脚本中,只要是我们特意跟踪这些名称的话,则还需要获取每一群集及其节点的信息。为此,我们需要使用 Compute Cluster Pack scripting API。

这样在开始遍历记录集之前,我们利用这次机会,使用编程标识符“Microsoft.ComputeCluster.Cluster”来创建基础 CCP API 对象的引用,这将会是所有 Compute Cluster Server 脚本编写爱好者耳熟能详之事。我们将再次检查错误,但如果再次发现错误的话,我们不会退出。将消息传给 HandleError,表明我们不能从发现的所有计算群集中获取群集和节点信息。脚本仍将继续运行,至少会列出其使用 ADO 获取的群集名称。

Set objComputeCluster = CreateObject("Microsoft.ComputeCluster.Cluster") 
If Err Then
  HandleError "ERROR: Unable to find Compute Cluster Pack API " & _
   "on this computer. Cluster and node settings not available."
End If

是的我们知道,好像到开始遍历记录集并寻找这些计算群集的时间了,但是还有一点需要注意。我们不想浪费时间去遍历那些不含记录的记录集,因为其中不会找到任何的计算群集。我们应该确保记录集对象的 EOF(文件结尾)属性为不真,这仅仅是一个双重否定方法,用于说明此处至少有一个记录。

If Not objRecordSet.EOF Then

好,现在可以正式开始。首先确保在记录集开始时调用 MoveFirst 方法。然后进行 Do Until 循环。该循环告诉 VBScript 引擎在“Do Until”和“Loop”之间执行操作,直到记录集中每个记录上都执行过此操作为止。每个循环都以检查是否到达了 EOF 开始,在此情况下,脚本结束循环并继续进行下一步。如果没有到达 EOF,则通过循环继续进行。每次脚本到达循环的末尾,都调用 MoveNext 方法移动到记录集中的下一条记录,然后在再次遍历之前,检查是否到达了记录集的末尾。

  objRecordSet.MoveFirst 
  Do Until objRecordSet.EOF
    ...
    objRecordSet.MoveNext
  Loop

在此循环内,对于每条记录,我们都依次将“servicednsname”字段的值转储为变量中并显示完整的 DNS 名称。这看起来好像“srv-ccs-1.computers.fabrikam.com”。

    strClusterDnsName = objRecordSet.Fields("servicednsname").Value
    Wscript.Echo vbCrLf & "Cluster DNS Name: " & strClusterDnsName

然后提取 VBScript 字符串分析函数:Left 和 InStr,并开始进行分割。使用 InStr 函数在字符串中查找第一个句号;使用 Left 函数将句号左边的字符串部分删除。我们将获取主机名,该名称同时还是计算群集的名称。

    strClusterName = Left(strClusterDnsName, _
     (InStr(strClusterDnsName, ".") - 1))

是的,我们知道,这种方法虽不同于正则表达式,但却很有效。如果真的喜欢在此处使用正则表达式,则 VBScript 可提供 RegExp 对象,以满足您的不同要求。

现在我们获取了容器中的计算群集记录集、每个群集的名称和群集对象引用。因此在每个循环中,我们都使用 Cluster.Connect 方法连接到群集并获取其属性。如果群集不可访问,则再次检查是否出现了错误。

    objComputeCluster.Connect(strClusterName)
    If Err Then
      HandleError "ERROR: Unable to connect to this compute cluster."
    Else

获取并回显群集属性后,我们使用 Cluster.ComputeNodes 方法获取本群集的节点集合。

      Set colNodes = objComputeCluster.ComputeNodes

这次我们使用 For Each 循环遍历节点集合,该语句对集合进行的操作与 Do Until 语句对记录集进行的操作一样。对于每个节点,我们都能获取其属性及其状态。

      For Each objNode In colNodes
        WScript.Echo "  Node: " & objNode.Name
        WScript.Echo "    Number of Processors: " & objNode.NumberOfProcessors
        WScript.Echo "    Processor Architecture: " & _
         objNode.ProcessorArchitecture
        WScript.Echo "    Processor Speed: " & objNode.ProcessorSpeed & " MHz"
        WScript.Echo "    Memory: " & objNode.Memory & " MB"
        strStatus = ""
        Select Case objNode.Status
          Case 0 strStatus = "Ready"
          Case 1 strStatus = "Paused"
          Case 2 strStatus = "Unreachable"
          Case 3 strStatus = "Pending Approval"
          Case Else strStatus = "Status unobtainable"
        End Select
        WScript.Echo "    Status: " & strStatus
      Next

关于此脚本的 CCP API 部分如何工作的详细信息,请参阅 Around the Nodes in 80 Scripts: A Grand Tour of the Compute Cluster Server Scripting Library(英文)

该脚本的结构与太阳系的结构有点类似。我们获取了关于记录集的大群集对象循环和关于每个群集的更小的节点对象循环。但是情况不断在变化。如果伽利略能够看到这个脚本,他也会被脚本复杂的结构弄的头晕目眩。

如果您决定使用此脚本,则需要将其复制到剪贴板并将其粘贴到文本文件,并以“.vbs”作为该文件的扩展名。务必在“CN=computers,DC=fabrikam,DC=com”处粘贴实际域或容器的名称。然后打开命令提示符并开始执行。注意,如果未将默认脚本宿主改为 Cscript.exe,则能够通过在脚本名称前加“cscript”,以批模式运行脚本。

cscript findclusters.vbs

下面是完整代码:

清单: 在 Active Directory 容器中查找群集并获取信息。

'List all computers in container running Compute Cluster Server and get 
'information on nodes of each.

On Error Resume Next

'Initialize constants and variables.
Const ADS_SCOPE_SUBTREE = 2
strContainer = "CN=computers,DC=fabrikam,DC=com" 'Accessible AD container.
strObjectCategory = "ServiceConnectionPoint" 'For CCS
strServiceClassName = "MicrosoftComputeCluster"

'Search ADsPath recursively for compute clusters with ADO.
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = ("ADsDSOObject")
objConnection.Open "Active Directory Provider"
objCommand.ActiveConnection = objConnection
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
objCommand.Properties("Sort On") = "cn"
'Construct SQL query.
objCommand.CommandText = _ 
 "SELECT serviceClassName,servicednsname FROM 'LDAP://" & _
 strContainer & "' " & _
 "WHERE objectCategory = '" & strObjectCategory & "' " & _
 "AND serviceClassName = '" & strServiceClassName & "'"
'Perform search of container.
Set objRecordSet = objCommand.Execute
If Err Then
  HandleError "ERROR: Unable to find container: " & strContainer
  WScript.Quit
End If
WScript.Echo "Searching AD container: " & strContainer & " ..."

'Create object reference to CCP API.
Set objComputeCluster = CreateObject("Microsoft.ComputeCluster.Cluster")
If Err Then
  HandleError "ERROR: Unable to find Compute Cluster Pack API " & _
   "on this computer. Cluster and node settings not available."
End If

'Check if returned record set is empty.
If Not objRecordSet.EOF Then
  objRecordSet.MoveFirst 
'Loop through compute clusters returned by query.
  Do Until objRecordSet.EOF
    strClusterDnsName = objRecordSet.Fields("servicednsname").Value
    Wscript.Echo vbCrLf & "Cluster DNS Name: " & strClusterDnsName
'Parse cluster name from DNS name.
    strClusterName = Left(strClusterDnsName, _
     (InStr(strClusterDnsName, ".") - 1))
    Wscript.Echo "Cluster Host Name: " & strClusterName
    
'Connect to cluster head node and get cluster properties.
    objComputeCluster.Connect(strClusterName)
    If Err Then
      HandleError "ERROR: Unable to connect to this compute cluster."
    Else
      WScript.Echo "Compute Cluster Name: " & objComputeCluster.Name
      WScript.Echo "Server calls asynchronous: " & _
       objComputeCluster.IsAsynchronous
      WScript.Echo "Compute Cluster Environment Variables:"
      Set colEnvVars = objComputeCluster.EnvironmentVariables
      For Each objEnvVar In colEnvVars
        WScript.Echo "  " & objEnvVar.Name & " = " & objEnvVar.Value
      Next
      WScript.Echo "Compute Cluster Parameters:"
      Set colParams = objComputeCluster.Parameters
      For Each objParam In colParams
        WScript.Echo "  " & objParam.Name & " = " & objParam.Value
      Next
      WScript.Echo "Compute Cluster Nodes:"
      Set colNodes = objComputeCluster.ComputeNodes
'Loop through nodes and get node properties.
      For Each objNode In colNodes
        WScript.Echo "  Node: " & objNode.Name
        WScript.Echo "    Number of Processors: " & objNode.NumberOfProcessors
        WScript.Echo "    Processor Architecture: " & _
         objNode.ProcessorArchitecture
        WScript.Echo "    Processor Speed: " & objNode.ProcessorSpeed & " MHz"
        WScript.Echo "    Memory: " & objNode.Memory & " MB"
        strStatus = ""
        Select Case objNode.Status
          Case 0 strStatus = "Ready"
          Case 1 strStatus = "Paused"
          Case 2 strStatus = "Unreachable"
          Case 3 strStatus = "Pending Approval"
          Case Else strStatus = "Status unobtainable"
        End Select
        WScript.Echo "    Status: " & strStatus
      Next
    End If

    objRecordSet.MoveNext 
  Loop 

Else
  Wscript.Echo "No records found."
End If

'******************************************************************************

Sub HandleError(strMessage)
'Handle errors passed from other parts of script.

strError = VbCrLf & VbCrLf & strMessage & _
 VbCrLf & "Number (dec) : " & Err.Number & _
 VbCrLf & "Number (hex) : &H" & Hex(Err.Number) & _
 VbCrLf & "Description  : " & Err.Description & _
 VbCrLf & "Source       : " & Err.Source
WScript.Echo strError
Err.Clear

End Sub

顺便说一下,如果想要精简脚本,则可在脚本存储库Compute Cluster Server 区域的节点部分中,请参阅不带错误处理或注释的简化版脚本。

收集群集

如果必须管理大量计算群集,则可使用刚才介绍的脚本建立群集和节点的基准列表,以便修改脚本,从而在文本文件、电子表格或数据库中存储列表(请参见“You Gotta Have Hertz: Preparing for Compute Cluster Server Deployment with Scripts - Part 2(英文)”中的 WriteTextFile 函数)。然后将脚本作为计划任务定期运行,并输出运行群集和节点的当前列表。可以相对简单地编写单独的脚本,以比较两个列表并将差异记录并通知给管理员。这样可以获取停止或离线的群集和节点,以及非正式添加的无赖群集和节点。

Scripto 博士:要不是这么难,就会请您来编写了!

细想起来,当您出去检查计算群集时,并没有进行过多的工作来扩展脚本,以监视采用 CCP API 和 Windows Management Instrumentation (WMI) 等其他脚本编写技术的所有群集和节点的情况。但那就要另当别论了。

如果您是熟悉(或者希望熟悉).NET Framework 的开发人员(或者有经验的脚本编写者),则您可以查找等效的 C# 编码,以便在 Windows HPC Community 站点上,从 Dennis Crain 的开发人员博客“Reading compute cluster headnode names from Directory Services(英文)”的目录中查找计算群集。

资源

Compute Cluster Server 和 Active Directory

Deploying and Managing Microsoft Windows Compute Cluster 2003(英文)

Compute Cluster Network Requirements(英文)

ActiveX 数据对象 ( ADO )

Scripting for Databases(英文)

Microsoft Windows 2000 Scripting Guide: Working with Databases(英文)

Microsoft ActiveX Data Objects (ADO) SDK(英文)

伙计,我的打印机在哪里:使用脚本在 Active Directory 中执行搜索

Active Directory Service Interfaces (ADSI)

Scripting for Active Directory(英文)

Microsoft Windows 2000 Scripting Guide: ADSI Scripting Primer(英文)

Active Directory Service Interfaces SDK(英文)

Compute Cluster Pack API

Around the Nodes in 80 Scripts: A Grand Tour of the Compute Cluster Server Scripting Library(英文)

Script Repository: Compute Cluster Server(英文)

Microsoft Compute Cluster Pack SDK(英文)