2009年6月25日木曜日

ILM2007のクラスタリング

ILM2007の冗長化って少し癖がありますので今回はそのご紹介を。。

基本的な考え方はILMサポートチームのブログでひろとさんが書いているのでそちらを見てもらうとして、、
http://blogs.technet.com/jpilmblg/archive/2008/09/29/miis-ilm.aspx
http://blogs.technet.com/jpilmblg/archive/2008/10/22/miis-ilm-2.aspx


ここで紹介されている情報を含め基本はSQL ServerのクラスタリングとコールドスタンバイでのILMの冗長化という構成がメーカサポートの限界っぽいのですが、ここではあえてサポートを気にせずILM自体のクラスタリングをしてみます。
(ということでNonサポートです)

<参考URL>
http://blogs.msdn.com/alextch/archive/2005/12/17/clusteredmiis.aspx
http://social.technet.microsoft.com/Forums/en-US/identitylifecyclemanager/thread/bb508bbd-ca49-4cf8-8159-bde0570098bf



まず、セットアップ前の準備ですが通常のインストールと違い、以下のポイントに注意が必要です。
・サービスアカウントはドメインユーザを利用する
 ※ローカルAdministrator権限は不要
・MIISAdminsなどのグループアカウントはドメイン上のグローバルグループを利用する
 ※インストール前にあらかじめ作成が必要
 ※以下のメンバを所属させておく必要あり
  ILMサービスアカウント
  クラスタサービスアカウント:MSCS経由で実行する際に必要
  尚、クラスタサービスアカウントは通常ローカルAdministrator権限は不要ですが、
  ILMを使う場合はローカルAdministrator権限が必要・・・

次にILMのセットアップですが、以下の順番に実施します。
1.プライマリノードでセットアップ
  データベースはリモートサーバを指定
  グループはあらかじめ作成したドメイングループを使用する(DOM\GROUP形式で指定)
2.プライマリノードでILMを停止
3.セカンダリノードでセットアップ
  データベースはリモートサーバを指定
  データベースの認識をする際にすでにデータベースが存在している旨が表示されるのでOKする




















  グループはあらかじめ作成したドメイングループを使用する(DOM\GROUP形式で指定)
  キーファイル(*.bin)プライマリノードで作成したものをコピーする
4.セカンダリノードでILMを停止
5.プラまりノードでILMを起動
  通常通りの起動方法だと、こんなエラーが出てしまう。








イベントログはこんな感じ


















  というわけで、起動方法は
  miisactivate.exe キーファイル サービスアカウント パスワード
  となります。(クラスタエージェントもこのコマンドをサイレントモードで実行します)


ここまで来たら次はクラスタへの組み込みです。

注意点は下記の通りです。
・登録するクラスタグループに優先ノードの設定を入れておく
 ※スクリプトの作りの問題です(設定していないとスクリプトがエラーを出すので必ず設定が必要)
・sleep.exeを使うのでWindows Server 2003のリソースキットが必要
・クラスタエージェント(下記のスクリプト)およびILMのキーファイルはILMインストールフォルダ\bin以下に
 配置する(miisactivate.exeと同一フォルダである必要がある)
・CSV MAなどを使う場合、MADATAフォルダはローカルにあるので、CSVファイルは必ず両方のサーバに配置するような仕組みが別途必要です
 ※インストールオプションでMADATAだけ共有ディスクに移動できないか試したのですが、どうやら無理でした。。。


早速のセットアップですが、以下の流れです。
・リソースの種類は「汎用スクリプト」を使用















・登録してオンラインにした状態















クラスタエージェントスクリプトはこんな感じです。(参考URLに載っているものに一部バグがあったので修正しています)

各関数の解説
関数名種別機能/解説
Openクラスタのエントリポイントエージェントがロードされた時に呼ばれる。
Onlineクラスタのエントリポイントリソースをオンラインにする時に呼ばれる。
実行されたノードがGetPrefferedOwners関数で取得した優先ノードでなかった場合、CheckMIISServiceStatus関数で優先ノードでILMが実行されるか確認、もし実行中だった場合はStopRunningProfiles、StopMIISService関数を使って優先ノード上のILMを停止する。
その上でMiisactivateコマンドでILMの起動を試み、CheckMIISServiceStatus関数で起動状態を確認する。
LooksAliveクラスタのエントリポイントクラスタのエントリポイント。リソースのポーリングを行う。
CheckMIISServiceStatus関数を呼び出してILMのサービス死活を監視する。
IsAliveクラスタのエントリポイントクラスタのエントリポイント。リソースのポーリングを行う。
GetNumberOfMVRecords関数を呼び出してILMのサービス死活を監視する。
Offlineクラスタのエントリポイントクラスタのエントリポイント。リソースをオンラインにする時に呼ばれる。
StopRunningProfiles関数を呼び出して実行中のプロファイルを停止し、StopMIISService関数でILMのサービスを停止する
Terminateクラスタのエントリポイントクラスタのエントリポイント。特に何もしない。
Closeクラスタのエントリポイントクラスタのエントリポイント。特に何もしない。
GetPrefferedOwnersプライベート関数WMI経由でMSCS関連のレジストリより優先ノード情報を取得する
CheckMIISServiceStatusプライベート関数WMI経由でmiiserverサービスの実行状態を取得する
StopMIISServiceプライベート関数WMI経由でmiiserverサービスを停止する
StopRunningProfilesプライベート関数WMI経由でILMに接続し、実行中のプロファイルがあれば停止する
GetNumberOfMVRecordsプライベート関数WMI経由でILMに接続し、Metaverseのオブジェクト数を確認する(ポーリング目的)


実際のスクリプト


Option Explicit
'##################################################################################
'GLOBAL DECLARATIONS - MODIFY ACCORDING TO YOUR ENVIRONMENT
'CLUSTER GROUP WHICH CONTAINS MIIS SQL AND SCRIPT RESOURCES
Dim miisgroup
miisgroup = "MSSQL" ' ILM2007リソースを作成するクラスタグループ名
Dim miisServiceAccount
miisServiceAccount = "mscs\ilmservice"  ' ILMサービスアカウント
Dim miisServiceAccountPwd
miisServiceAccountPwd = "P@ssw0rd"  ' ILMサービスアカウントのパスワード
Dim miisEncryptKey
miisEncryptKey = "miiskey.bin"
Dim miisServiceStartupTime 'time in seconds for MIIS Service to come up
miisServiceStartupTime = 400

'###################################################################################
Dim activeNode
Dim prefferedOwners
Dim miisActivateCmd


Function Open()
  Dim WshNetwork

  Resource.LogInformation("Entering Open() for group" & Resource.Name)
  Set WshNetwork = CreateObject("WSCript.Network")
  activeNode = WshNetwork.ComputerName
  prefferedOwners = GetPrefferedOwners()
  miisActivateCmd = "miisactivate.exe " & miisEncryptKey & " " & miisServiceAccount & " " & miisServiceAccountPwd & " /q"
  Resource.LogInformation("MIISActivate Command - " & miisActivateCmd)
  Open = True

End Function

Function Online( )
  Dim Node
  Dim WshShell
  Dim oExec
  Dim oWait
  Dim i

  Resource.LogInformation("Entering Online()")

  'Ensurting that MIIS Service is not running on other preffered nodes of the cluster grp
  For Each Node In prefferedOwners
    If (Node <> activeNode) And (CheckMIISServiceStatus(Node) = True) Then
      StopRunningProfiles(Node)
      StopMIISService(Node)
    End If
  Next

  'Check if MIIS Service is already running on the active Node, if yes just exit
  If CheckMIISServiceStatus(activeNode) = True Then
    Online = True
    Exit Function
  End If

  'Run MIISActivate on the Active Cluster Noded
  Resource.LogInformation("About to execute:" & miisActivateCmd)
  Set WshShell = CreateObject("WScript.Shell")
  WshShell.CurrentDirectory = "C:\Program Files\Microsoft Identity Integration Server\Bin"
  Set oExec = WshShell.Exec(miisActivateCmd)
  ' ... Allow time for operation to complete...
  For i = 0 To miisServiceStartupTime
    Resource.LogInformation("Waiting for MIIS Service to come-up...")
    WshShell.Run "sleep 5" ,0,True
    If CheckMIISServiceStatus(activeNode) = True Then
      Resource.LogInformation("MIIS Service Started by MIISMonitor Script")
      Exit For
    End if
  Next

  If CheckMIISServiceStatus(activeNode) = False Then
    Resource.LogInformation("Failed to MIISActivate on Node:" & activeNode)
    Online = False
  Else
    Resource.LogInformation("MIISActivated on Node:" & activeNode)
    Online = True
  End If

End Function

Function LooksAlive()

  If CheckMIISServiceStatus(activeNode) = True Then
    Resource.LogInformation("MIIS Service LooksAlive")
    LooksAlive = True
  Else
    Resource.LogInformation("MIIS Service Failed")
    LooksAlive = False
  End If

End Function

Function IsAlive()

  'Perform various MIIS calls to ensure that it is alive
  If GetNumberOfMVRecords(activeNode) = True Then
    Resource.LogInformation("MIIS Service is Alive")
    IsAlive = True
  Else
    Resource.LogInformation("MIIS Service failed isAlive check")
    IsAlive = False
  End If

End Function

Function Offline()

  Resource.LogInformation("Entering Offline()")
  Resource.LogInformation("About to stop MIIS Service on node:" & activeNode)
  StopRunningProfiles(activeNode)
  StopMIISService(activeNode)

End Function

Function Terminate()

  Terminate = True

End Function

Function Close()

  Close = True

End Function

Function GetPrefferedOwners()
  Const HKEY_LOCAL_MACHINE = &H80000002
  Dim oReg
  Dim strKeyPath
  Dim arrSubKeys
  Dim strValueName
  Dim strValue
  Dim arrValues
  Dim subkey
  Dim strPrefferedNodes()
  Dim i
  i = 0

  Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
  activeNode & "\root\default:StdRegProv")

  strKeyPath = "Cluster\Groups\"
  oReg.EnumKey HKEY_LOCAL_MACHINE, strKeyPath, arrSubKeys

  For Each subkey In arrSubKeys
    strKeyPath = "Cluster\Groups\" & subkey
    strValueName = "Name"
    oReg.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
    If strValue = miisgroup Then
      strValueName = "PreferredOwners"
      oReg.GetMultiStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,arrValues
      For Each strValue In arrValues
        strKeyPath = "Cluster\Nodes\" & strValue
        strValueName = "NodeName"
        oReg.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
        ReDim Preserve strPrefferedNodes(i)
        strPrefferedNodes(i) = strValue
        i = i + 1
      Next
    End If
  Next

  GetPrefferedOwners = strPrefferedNodes

End Function

Function CheckMIISServiceStatus(Node)
On Error Resume Next

  Dim objWMIService
  Dim strWMIQuery
  Dim colServices

  Set objWMIService = GetObject("winmgmts:" _
  & "{impersonationLevel=impersonate}!\\" & Node & "\root\cimv2")
  strWMIQuery = "Select * from Win32_Service where Name = 'miiserver' and State = 'running'"
  Set colServices = objWMIService.ExecQuery(strWMIQuery)
  If Err.Number <> 0 Then
    Resource.LogInformation("Unable to complete WMI call in CheckMIISServiceStatus, error code " & Err.Number)
    CheckMIISService = False
    Exit Function
  End If

  If colServices.Count = 1 Then
    CheckMIISServiceStatus = True
  Else
    CheckMIISServiceStatus = False
  End If

End Function

Function StopMIISService(Node)
On Error Resume Next

  Dim objWMIService
  Dim colServiceList
  Dim objService

  Set objWMIService = GetObject("winmgmts:" _
  & "{impersonationLevel=impersonate}!\\" & Node & "\root\cimv2")
  Set colServiceList = objWMIService.ExecQuery _
  ("Select * from Win32_Service where Name='miiserver' and State = 'running'")

  For Each objService In colServiceList
    objService.StopService()
    If Err.Number <> 0 Then
      Resource.LogInformation("Unable to complete WMI call to stop MIIS during StopMIISService, error code " & Err.Number)
    End If
  Next

End Function

Function StopRunningProfiles(Node)
On Error Resume Next

  Dim objWMIService
  Dim Runs
  Dim Run
  Dim ManagementAgent

  'First stop all running jobs
  Set objWMIService = GetObject("winmgmts:" _
  & "{impersonationLevel=impersonate}!\\" & Node & "\root\MicrosoftIdentityIntegrationServer")
  Set Runs = objWMIService.ExecQuery("Select * From MIIS_RunHistory where RunStatus = 'in-progress'")

  For Each Run in Runs
    Resource.LogInformation("Stopping " & Run.MaName & " profile " & Run.RunProfile)
    Set ManagementAgent = objWMIService.Get("MIIS_ManagementAgent.Name='" & Run.MaName & "'")
    ManagementAgent.Stop()
    If Err.Number <> 0 Then
      Resource.LogInformation("Unable to complete WMI to get Run History call during StopRunningProfiles, error code " & Err.Number)
    End If
  Next

End Function

Function GetNumberOfMVRecords(Node)

  Dim Service
  Dim Server
  Dim numOfMvObjects

  Set Service = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & Node & "\root\MicrosoftIdentityIntegrationServer")
  Set Server = Service.Get("MIIS_Server.Name='MIIS_Server1'")
  numOfMvObjects = Server.NumMvObjects()

  If numOfMvObjects = "connection-failure" Or numOfMvObjects = "call-failure:0x80230621" Then
    Resource.LogInformation("Unable to complete WMI call in isAlive, error code " & Err.Number & ":" & numOfMvObjects )
    GetNumberOfMVRecords = False
  Else
    Resource.LogInformation("Count of Metaverse Objects = " & numOfMvObjects)
    GetNumberOfMVRecords = True
  End If


End Function

0 件のコメント: