2022/04/23

入れ子グループのループを見つける

ドミノディレクトリに登録するグループでは、そのメンバーに他のグループ名を指定することができます。

グループ文書のメンバー欄は他のテキストフィールドと同様に文字数制限があります。その制限を超えて多くのメンバー名を登録したい等の理由でグループから別のグループを参照する「グループの入れ子」を行うことがあります。

分かりづらいですが、次に例を示します。「Grp1」のメンバーに「Grp2」を指定しています。そして「Grp2」のメンバーに「Grp3」を指定、「Grp3」のメンバーに「Grp4」を指定...と続きます。

Grp1
└Grp2
 └Grp3
  └Grp4
   ├Grp2
   └Grp5
    └Grp6

入れ子のグループ自体は結構なのですが、気が付くと2つのグループが互いに参照しあって、参照のループを起こしていることがあります。

上の例では「Grp4」のメンバーに「Grp2」を指定していて、Grp2 から Grp4 の間で参照のループを起こしています。

私はこういった参照のループが運用上問題になることは最近はほとんど経験していません。が、新機能のベータ版で不具合を引き起こしたことがありました。

そんなときに参照のループをチェックするツールが欲しいな、ということで作ったコードがありますのでご紹介します。


Dim nab As NotesDatabase
Dim vw As NotesView
Dim groupsInThread% List
Dim loopGroups$ List 
Sub Initialize
	Dim ss As New NotesSession
	Dim dc As NotesDocumentCollection
	Dim currentGroup As NotesDocument
	Dim searchFormula$

	Set nab = New NotesDatabase( ss.Currentdatabase.Server, "names.nsf" )
	Set vw = nab.Getview( "Groups" )
	searchFormula = |Form="Group"|
	If Not nab.Isopen Then Call nab.Open("", "")
	Set dc = nab.Search( searchFormula, Nothing, 0 )
	Set currentGroup = dc.Getfirstdocument()
	While Not currentGroup Is Nothing
		Call isLoop( currentGroup, 0 )
		Erase groupsInThread
		Set currentGroup = dc.Getnextdocument( currentGroup )
	Wend
	
	ForAll o In loopGroups
		Print ListTag( o ), o
	End ForAll
	
End Sub

Function isLoop( currentGroup As NotesDocument, nestLevel% ) As String
	Dim childGroup As NotesDocument
	Dim members, groupName$, loopingMember$
	isLoop = ""
	groupName = currentGroup.Getfirstitem( "ListName" ).Text

	'Existing check for group name
	If IsElement( loopGroups( groupName ) ) Then Exit Function
	If IsElement( groupsInThread( groupName ) ) Then
		loopGroups( groupName ) = ""
		isLoop = groupName
		Exit Function
	Else
		groupsInThread( groupName ) = False
	End If

	'Check group members
	If "" = currentGroup.Getfirstitem( "Members" ).Text Then Exit Function
	members = currentGroup.Getfirstitem( "Members" ).Values
	ForAll member In members
		If "cn=" <> LCase( Left( member, 3 ) ) Then
			Set childGroup = vw.Getdocumentbykey( member, True )
			If Not childGroup Is Nothing Then
				loopingMember = isLoop( childGroup, nestLevel + 1 )
				if "" <> loopingMember Then
					If groupName <> loopingMember Then
						isLoop = loopingMember
					End If
					If Not IsElement( loopGroups( member ) ) Then
						loopGroups( member ) = loopingMember
					End If
				End If
			End If
		End If
	End ForAll
	Erase groupsInThread( groupName )
End Function


これをエージェントにして実行すると、参照のループが始まるグループ(上の例では Grp2)はそのグループ名だけ表示します。そして、参照のループの途中にあるグループ(Grp4)と参照のループの最後のグループ(Grp5)には、そのグループ名に加えて参照のループが始まるグループ名を一緒に表示します。

下図は私の環境でテストした結果です。print文の出力が Notes クライアントの通知ウィンドウ内に表示されています。参照のループが始まっているのは「Nested Group 05」と「Nested Group 15」です。


HCL Domino 12.0 に「Entitlement Scan」という機能があります。この機能でサーバー上にあるアプリケーションを定期的にスキャンするのですが、そのときグループに参照のループがあるとコンソールにメッセージ「Groups cannot be nested more than 100 levels deep.」を記録します。このメッセージにグループ名は記録されません(下図)。


このメッセージが表示される場合、上のようなコードを使って参照のループを調べてみてはいかがでしょうか。

0 件のコメント:

コメントを投稿