ゼロからのスクリプト作成: Jython による IBM WebSphere Application Server 向けの管理スクリプトの作成

IBM® WebSphere® Application Server の管理スクリプトをゼロから作成することは難しくはありませんが、作成プロセスの各ステップに関する実用的な情報はなかなか入手できません。この記事はまさにそのために役立ちます。スクリプトで何がしたいかを考えることからスタートし、反復的な開発ステップを進めていきます。これにより、最終的にコメントや使用方法の情報が記載され、コマンドライン・パラメーターの処理が含まれるサンプル・スクリプトが完成します。

Bob Gibson, Advisory Software Engineer, IBM

Bob GibsonはAdvisory Software Engineerであり、IBMの中で、四半世紀に渡って様々なソフトウェア関連業務を経験してきました。その一部には、アプリケーション・プログラマーやアーキテクト、開発者、インストラクター、テクニカル・サポート・アナリスト、テスターなどがあります。彼は現在、IBM WebSphere Distributed Application Serverを担当するテクニカル・サポート・グループのチーム・リーダーです。University of Virginiaにて、エンジニアリング・サイエンスの学位とコンピューター・サインエスの修士を取得しています。



2010年 4月 07日

はじめに

Jython を使用した WebSphere Application Server の管理に関する本を書く前から、完全なスクリプトの作成に取り掛かる方法を解説した例がほとんどないことに気付いていました。そこで、そのようなスクリプト作成のために、私が何度も使用してきたプロセスについて解説すれば、向上心あふれる wsadmin スクリプト作成者の役に立つのではないかと考えました。

一般に、wsadmin スクリプトをゼロから作成するには、概要レベルで次のステップを実行する必要があります。

  1. 遂行したい管理タスクを決定する。
  2. ドキュメントに目を通して、その管理タスク、および使用できるさまざまなメソッドについて学習する。
  3. メソッドのパラメーターを確認し、その使用方法を理解する。
  4. 対話モードの wsadmin セッションを使用して、メソッド、メソッドの使用方法、およびメソッドのパラメーター値を確認し、試してみる。
  5. スクリプト・テンプレートを使用して、スクリプトにメソッドのパラメーター値を割り当てる最適なテクニック (例えば、プロパティ・ファイルやコマンドライン・パラメーターによる受け渡し) を決定する。
  6. パラメーター処理コードや使用方法の詳細をスクリプトに追加する。
  7. 目的のタスクを遂行する実際のスクリプト・メソッドを実行するコードを追加する。

デモンストレーション用に、この記事では、クラスター・メンバーを作成できるスクリプトを作成するために、実行するステップを解説します。とても単純明快なタスクですが、多くのタスクと同様に、タスクを複雑にする要因がないわけではありません。例えば、そのスクリプトではクラスター・メンバーを 1 つだけ作成できればよいのか、それとも複数のメンバーを同時に作成できるようにするのか、ということなどです。

この記事で解説するステップをたどることで、シンプルにスタートし、最終的にはクラスター・メンバーを 1 つ作成できるサンプル・スクリプトを作成します。

この記事は IBM WebSphere Application Server V7.0 および V6.1 の両方に適用されます。


アプローチを決める

スタートにあたっての考え方として、最初に興味のあるタスクに関する情報を探します。そうすると、その情報から、関係のあるプロセスやパラメーターを理解できるようになります。また、適切かつ効果的なやり方でそのタスクを遂行するスクリプトを作成できるようになります。

例えば、Web ブラウザーを使用して、IBM WebSphere Application Server V7 Network Deployment インフォメーション・センターにアクセスし、「クラスター・メンバーの作成」という語句を検索します。結果は上々で、「スクリプトによるクラスター・メンバーの作成」というトピックが検索結果のトップに表示されます。最初のこのようなリンクを選択し、関連ドキュメントを表示します。

  • 始める前に」セクションには、この作業のために複数のアプローチがあることが説明されています。例えば、新しいクラスター・メンバーを作成するには、次のアプローチを採用することができます。
  • さらに、「このタスクについて」セクションには、次のような興味深い問題が提起されています。
    • どのくらい汎用的なスクリプトにするか (する必要があるか)。
    • スクリプトでは、クラスターの最初のメンバー、後続のメンバーのみ、またはその両方を作成できるようにするか。
    • スクリプトを続行するために既存のクラスターが必要か、またはスクリプトのプロセスの一部として新しいクラスターを作成できるようにするか (する必要があるか)。

進め方を決定する前に、各アプローチを見てみることにしましょう。

AdminConfig スクリプト・オブジェクトの使用

このタスクで AdminConfig スクリプト・オブジェクトを何らかの形で使用することは明らかなので、まずインフォメーション・センターで関連情報を検索することをお勧めします。

AdminConfig」を検索すると、生成された複数の検索結果の上位に「wsadmin スクリプトを使用する AdminConfig オブジェクトのコマンド」というトピックがあります。このトピックを読むと、AdminConfig スクリプト・オブジェクトに createClusterMember メソッドがあることが明らかになります。先へ進むと、このメソッドにいくつかの必須パラメーターがあることがわかります。使い方をもっとよく理解するには、そのページのさらに下にある例をざっと眺めてください。興味深いことに、必須パラメーターの一覧 (表 1) はサンプル・コードと対応していません。

表 1. AdminConfig.createClusterMember() の必須パラメーター
パラメーター名説明
clusterIDメンバーを追加するクラスターの構成 ID。
nodeIDメンバーを作成するノードの構成 ID。
memberAttributes新しいメンバーの作成に使用する属性を指定します。
templateIDメンバーの作成プロセスで使用するテンプレートの構成 ID。

templateID パラメーターが本当に必須なら、サンプル・コードからどうして省略できるのでしょうか。実は、templateID パラメーターはクラスターの最初のメンバーにのみ使用することができ、後続のクラスター・メンバーの作成では、最初のメンバーがテンプレートとして使用されます。

提供されるサンプル・スクリプトについて
サンプル・スクリプトを使用すると、1 つのメンバーを含む必須クラスターの作成の仕組みではなく、目的のスクリプトの作成プロセスに集中し続けることができます。この記事のスクリプトでは、1 つのクラスター (Cluster1) とその最初のメンバー (Member1) が作成済みであることが前提になっています。また、これらのスクリプトはこの記事で説明するプロセスを使用して作成されているので、学習のための追加の例としても活用できます。

ただし、クラスター・メンバーを作成するためには、まずクラスターを作成し、その最初のクラスター・メンバーを作成する必要があります。その実行に役立てるため、この記事に記載されているダウンロード資料に含まれる次のスクリプト (およびここで説明するテクニックを使用して作成されたスクリプト) を使用できます。

  • createCluster.py: 空のクラスターを作成します。
  • createFirstClusterMember.py: ユーザーが指定したテンプレート名で最初のクラスター・メンバーを作成します。

ここで、対話モードの wsadmin セッションを使用して、AdminConfig.createClusterMember() メソッドによる新しいクラスター・メンバーの作成に必要なステップを見ていきましょう。リスト 1 にこの対話セッションを、表 2 にこのセッションの詳細な説明を示します。

リスト 1. AdminConfig.createClusterMember() の使用
 1|[root@ragdoll bin]#./wsadmin.sh -lang jython
 2|WASX7209I: Connected to process "dmgr" on node ragdollCellManager02 using SOAP
 3|connector; The type of process is: DeploymentManager
 4|WASX7031I: For help, enter: "print Help.help()"
 5|
 6|wsadmin>print AdminConfig.list( 'ClusterMember' )
 7|Member1(cells/ragdollCell02/clusters/Cluster1|cluster.xml#ClusterMember_1261105354124)
 8|
 9|wsadmin>clusterID = AdminConfig.getid('/ServerCluster:Cluster1/' )
10|wsadmin>nodeID = AdminConfig.getid( '/Node:ragdollNode03/' );
11|wsadmin>memberID = AdminConfig.createClusterMember(clusterID, nodeID, '[[memberName
   Member2]]' )
12|wsadmin>print AdminConfig.list( 'ClusterMember' )
13|Member1(cells/ragdollCell02/clusters/Cluster1|cluster.xml#ClusterMember_1261105354124)
14|Member2(cells/ragdollCell02/clusters/Cluster1|cluster.xml#ClusterMember_1261145939139)
表 2. AdminConfig.createClusterMember() の使用の説明
コメント
1wsadmin を起動し、言語として Jython を指定します。
2-4wsadmin によって生成された、デプロイメント・マネージャーへの接続成功を示す情報です。
5読みやすさのために追加された空白行です。
6-7既存のクラスター・メンバー構成 ID を表示するために AdminConfig.list() を呼び出します。
8読みやすさのために追加された空白行です。
9-10メンバーを追加するクラスターの構成 ID と、メンバーを作成するノードの構成 ID を取得するための代入ステートメントです。
11新しいクラスター・メンバーを作成するために AdminConfig.createClusterMember() メソッドを呼び出します。
12-13新しく作成されたクラスター・メンバー (Member2) が存在することを示すために AdminConfig.list() を呼び出します。

このテクニックを使用して 1 つのクラスター・メンバーを作成するには、スクリプトでは以下のことが実行される必要があります。

  1. コマンドライン・パラメーターを確認する。
  2. clusterName コマンドライン・パラメーターを指定して、クラスター構成 ID を検索する (スクリプトでは構成 ID ではなく、クラスター名とノード名を指定するようユーザーに要求する必要がある)。
  3. nodeName コマンドライン・パラメーターを指定して、ノード構成 ID を検索する。
  4. 場合によっては、指定された memberName がクラスターにまだ存在しないことを確認する。
  5. 目的の操作を行うために、createClusterMember メソッドを実行する。
  6. リクエストが成功したか、失敗したかを確認する。

当然ながら、これは大雑把なプロセスにすぎませんが、この特定のテクニックを使うために、どのような種類のコーディングが必要かがわかります。しかし、このアプローチを使用したスクリプトの実装に時間や労力をかける前に、別のアプローチを調べて、両者にどのような違いがあるか、一方の実装が他方の実装より適切で簡単かどうかを見ていきましょう。

AdminTask スクリプト・オブジェクトの使用

再びインフォメーション・センターで、今度は「AdminTask」という用語を検索します。検索結果は 200 件を超えるので、「AdminTask オブジェクトの ClusterConfigCommands コマンド・グループ」というトピックを見つけるには少し下へスクロールする必要があります。このトピックを選択すると、ページのさらに下の方に createClusterMember メソッドへのリンクがあります。このセクションは、以下に示すこのメソッドの使用方法を理解するために役立ちます。

  • 最初のクラスター・メンバーを作成するには、次のいずれかを実行する必要があります。
    • アプリケーション・サーバーのテンプレート名を指定する (テンプレート名を指定すると、構成 ID を検索する必要がなくなります。というのは、AdminTask スクリプト・オブジェクトが代わりに実施するからです)。
    • テンプレートとして使用する既存のアプリケーション・サーバーを指定する。
  • 次のいずれかを指定できます。
    • クラスターの名前。
    • メンバーを追加するクラスターの構成 ID。
  • 異なるバージョンの WebSphere Application Server (V6.1 と V7.0) でクラスター・メンバーを持つことができますが、このシナリオについてはこの記事では説明しません。

異なるアプローチ間で意味のある比較をするため、比較対象となる実際のタスクをすべてのアプローチで同じにします。このケースでは、追加のクラスター・メンバーを作成できるスクリプトの作成方法です。つまり、テンプレート関連のパラメーターは無視して、後続のクラスター・メンバー作成に関連するパラメーターにのみ集中します。

スクリプト・オブジェクトのメソッドを使用してクラスター・メンバーを作成するつもりなら、使用可能なパラメーターについて理解する必要があります。これに関するドキュメントはわかりにくいので、対話モードの wsadmin セッションを活用して理解を深めるようにしてください。

AdminTask スクリプト・オブジェクトに関して本当に強力で役立つことの 1 つは、ほとんどすべてのメソッドにパラメーター定義を「ステップ・スルー」する手段が組み込まれていることです。このためには、パラメーターとして -interactive だけを指定して、メソッドを呼び出します。今度はこのテクニックを使用して、クラスター構成 ID を使用する場合と、クラスター名を使用する場合の違いを、 createClusterMember() メソッドに関連付けて学びます。

まず、リスト 2a の 1 行目と同じようにメソッドを呼び出します (この wsadmin セッション中に生成される行数が多いため、ここではリスト 2a から 2e までに分割しています)。

リスト 2a. 対話モードでのクラスター・メンバーの作成
 1|wsadmin>M1 = AdminTask.createClusterMember( '-interactive' )
 2|Create Cluster Member
 3|
 4|Creates a new member of an application server cluster.
 5|
 6|Cluster Object ID: Cluster1(cells/ragdollCell02/clusters/Cluster1|cluster.xml#Server
   Cluster_1261065198076)

対話モードでの呼び出しの結果は、1 つの変数に代入されます (リスト 2a、1 行目)。これは、対話モードでパラメーターを指定すると、その結果の AdminTask.createClusterMember() の呼び出しが、最終的に指定するすべてのパラメーターを含む実際の呼び出しになるからです。呼び出しの結果は、新しく作成されたクラスター・メンバーの構成 ID になります。

6 行目は AdminTask スクリプト・オブジェクトが情報の入力を求めており、クラスター・オブジェクト ID (つまり、新しいメンバーが追加されるクラスターの構成 ID) の値が必要であることを知らせています。構成 ID を指定したときにこのコマンドがどう見えるかを知るために、このプロンプトへの応答に、クラスターの完全な構成 ID をコピー・アンド・ペーストしてください (無効または未知の構成 ID を指定すると、例外が発生して wsadmin> プロンプトに制御が戻ります。AdminTask の対話テクニックでは変数名を使用できないので、ここで示す構成 ID などの値は明示的に指定する必要があります)。

この対話セッションの続きであるリスト 2b では、メンバーを作成するクラスターの名前の入力を求められます。クラスターはその構成 ID によってすでに特定されているので、クラスター名を指定する必要はありません。したがって、Enter を押すだけでかまいません (リスト 2b、1 行目)。

リスト 2b. 対話モードでのクラスター・メンバーの作成
 1|Cluster Name (clusterName):
 2|Create Cluster Member
 3|
 4|Creates a new member of an application server cluster.
 5|
 6|-> *1. Member Configuration (memberConfig)
 7|    2. First Member Configuration (firstMember)
 8|    3. Promote Proxy Server Settings To Cluster (promoteProxyServer)
 9|    4. Configure the event service during cluster member creation. (eventServiceConfig)
10|
11|S (Select)
12|N (Next)
13|C (Cancel)
14|H (Help)
15|
16|
17|Select [S, N, C, H]: [S]

この結果、サブメニューとして選択可能なステップ (6 行目から 9 行目)、選択可能な入力オプション (11 行目から 14 行目)、および入力を求めるコマンド・プロンプト (17 行目、右の角かっこ内がデフォルト選択項目) が表示されます。

ステップ 1 の横のアスタリスク (*) は、入力が必須であることを示します。デフォルト・コマンドが S (選択) であることに注意してください。Enter を押すか、文字 SEnter を押すと、指定したステップが実行され、リスト 2c に示す情報が表示されます。

リスト 2c. 対話モードでのクラスター・メンバーの作成
 1|Member Configuration (memberConfig)
 2|
 3|*Node Name (memberNode):
 4|*Member Name (memberName):
 5|Member Weight (memberWeight):
 6|Member UUID (memberUUID):
 7|Generate Unique HTTP Ports (genUniquePorts): [true]
 8|enable data replication (replicatorEntry): [false]
 9|Specific short name of cluster member (specificShortName):
10|
11|
12|Select [C (Cancel), E (Edit)]: [E]

リスト 2c の 1 行目に、選択したステップの説明とステップ名が表示され、3 行目から 9 行目に、現在のステップ属性に対する現在の値が表示されます。ここでも、必須の値の前にアスタリスクが付いています。いくつかの必須属性の値をまだ規定する必要があるので、デフォルト・コマンドは E (編集) です (12 行目)。この時点で Enter を押すと、必須の値が未指定であることが通知されます。リスト 2d に、これらの入力結果とそれへの応答を示します (1 行目から 8 行目)。この場合、入力されたのは必須属性の値のみです (1 行目から 2 行目)。

リスト 2d. 対話モードでのクラスター・メンバーの作成
 1|*Node Name (memberNode): ragdollNode03
 2|*Member Name (memberName): Member2
 3|Member Weight (memberWeight):
 4|Member UUID (memberUUID):
 5|Generate Unique HTTP Ports (genUniquePorts): [true]
 6|enable data replication (replicatorEntry): [false]
 7|Specific short name of cluster member (specificShortName):
 8|Create Cluster Member
 9|
10|Creates a new member of an application server cluster.
11|
12|    1. Member Configuration (memberConfig)
13|->  2. First Member Configuration (firstMember)
14|    3. Promote Proxy Server Settings To Cluster (promoteProxyServer)
15|    4. Configure the event service during cluster member creation. (eventServiceConfig)
16|
17|S (Select)
18|N (Next)
19|P (Previous)
20|F (Finish)
21|C (Cancel)
22|H (Help)
23|
24|
25|Select [S, N, P, F, C, H]: [F]

最後の応答後、「Create Cluster Member (クラスター・メンバーの作成)」サブメニューが再表示され、今度は次のステップを示す箇所に矢印 (->) が付いています。このケースでは次はステップ 2 です (13 行目)。必須の属性値はすべて指定されたので、今度は新しいコマンド「F (完了)」(20 行目) が選択可能になり、デフォルト・コマンドになっている (25 行目) ことに注目してください。

F (完了) コマンドを選択すると、対話モードでのメソッドの最終段階が開始され、最終的に生成されたコマンドが表示されます。結果をリスト 2e に示します。

リスト 2e. 生成された createClusterMember コマンド
WASX7278I: Generated command line: AdminTask.createClusterMember('Cluster1(cells/ragdoll
Cell02/clusters/Cluster1|cluster.xml#ServerCluster_1261065198076)', '[-memberConfig
[-memberNode ragdollNode03 -memberName Member2 -genUniquePorts true -replicatorEntry
false]]')

このコマンドは長いので、わかりやすく分解して見ていきましょう。コマンドの基本形は次のとおりです。

AdminTask.createClusterMember( TargetObject, Parameters )

TargetObject は、見てのとおり、新しいメンバーが追加されるターゲット・クラスターの構成 ID です。Parameters 値はもう少し複雑ですが、次の形式の文字列です。

‘[-memberConfig [values]]’

memberConfig には見覚えがあるかもしれません。リスト 2b (6 行目)、リスト 2c (1 行目)、およびインフォメーション・センターのドキュメントの「ステップ」サブセクションにも登場しています。ここではドキュメントを createClusterMember 対話セッションと対比させて、パズルのピースがどのように当てはまるかを確認できます。また、生成されたコマンドにはいくつかのデフォルト値 (例えば、genUniquePorts や replicatorEntry) が含まれていることもわかります。これらはデフォルトであり、作成するスクリプトで値を提供する必要があるかどうかは後で決定できます。

ここでは、対話モードで createClusterMember() メソッドを使用してきたので、クラスター構成 ID を使用することにした場合に、どのようなコマンドになるかを正確に確定することができます。同様に、clusterName パラメーターを代わりに使用した場合にはどのようなコマンドになるかもわかります。このために必要なのは、AdminConfig.reset() メソッドを使用して新しく作成したクラスター・メンバーを廃棄し、AdminTask.createClusterMember( '-interactive' ) メソッドを再実行するだけです。ただし、今度はクラスター構成 ID の代わりに、clusterName パラメーターを指定します。この実行結果をリスト 3 に示します。

リスト 3. 別の createClusterMember コマンド
WASX7278I: Generated command line: AdminTask.createClusterMember('[-clusterName Cluster1
-memberConfig [-memberNode ragdollNode03 -memberName Member1 -genUniquePorts true
-replicatorEntry false]]')

このコマンドの形式は次のようになります。

AdminTask.createClusterMember( Parameters )

この形式の Parameters 文字列は次のようになります。

‘[-clusterName value -memberConfig [values]]’

実のところ、-memberConfig の値はさきほどの値とまったく同じです。これは、-clusterName パラメーターは必須であるとしたオンライン・ドキュメントをさらに理解するために役立ちます (–clusterName パラメーターの説明では、TargetObject または –clusterName 値のいずれかを指定する必要があることが示されています。実際に両方を指定すると、例外がスローされ、コマンドは実行されません)。

うまく行けば、この試みは createClusterMember() メソッド、その対話モードでの実行、および関連ドキュメントを理解するために役立つでしょう。同じテクニックを使用して、2 番目のクラスター・メンバーを作成できます。さきほど実行したコマンドと違うのは、作成するメンバーの名前だけです。

これを実行すると、AdminTask.createClusterMember() メソッドを使用して、追加クラスター・メンバーを作成するために、スクリプトで処理する必要があるのは次のパラメーターであることがわかります。

  • 変更するクラスターの名前。
  • メンバーを作成するノードの名前。
  • 作成するメンバーの名前。

この記事の目的と簡略化のため、他のすべての値はデフォルト値をそのまま使用します。

これで、このアプローチによるスクリプトの作成をかなりよく理解できたはずです。

scriptLibraries の使用

クラスター・メンバーを作成するタスクを遂行するために検討できる 3 番目のアプローチは、AdminClusterManagement スクリプト・ライブラリーの createClusterMember メソッドを使用することです。scriptLibraries は WebSphere Application Server V7 に既に存在するので、このアプローチを使用すると、最小限の労力で要件を満たせる可能性があります。本当にこの方法でうまく行くかどうかをさっそく調べてみましょう。

インフォメーション・センターで「AdminClusterManagement」を検索すると、「Jython スクリプト・ライブラリー: wsadmin スクリプトを使用するクラスター管理スクリプト」というトピックが見つかります。このトピックは、ライブラリー・モジュール内の createClusterMember メソッドを含むいくつかのメソッドについての説明で、ちょうど探していた情報のようです。

これをテストするには、1 つ以上のメンバーを持つクラスターを 1 つ以上持つデプロイメント・マネージャー構成が必要です。この構成は既に存在するので、このアプローチを試す準備はすっかりできているようです。リスト 4 に、この状況のテストに使用する対話モードでの wsadmin セッション例を示します。また表 3 に、各ステップの詳細な説明を示します。

リスト 4. scriptLibrary メソッドの対話モードでの wsadmin によるテスト
 1|C:\IBM\WebSphere\AppServer70\bin>wsadmin –lang jython
 2|WASX7209I: Connected to process "dmgr" on node ragweedCellManager02 using SOAP
 3| connector;  The type of process is: DeploymentManager
 4|WASX7031I: For help, enter: "print Help.help()"
 5|wsadmin>cluster, node, member = 'Cluster1', 'ragweedNode03', 'Member2'
 6|wsadmin>AdminClusterManagement.createClusterMember( cluster, node, member )
 7|----------------------------------------------------------------------
 8| AdminClusterManagement:         Create a new cluster server member
 9| Cluster name:                   Cluster1
10| Member node name:               ragweedNode03
11| New member name:                Member2
12| Usage: AdminClusterManagement.createClusterMember("Cluster1", "ragweedNode03", ...
13| Return: The configuration ID of the new cluster member.
14|-----------------------------------------------------------------------
15|
16|
17|'Member2(cells/ragweedCell02/clusters/Cluster1|cluster.xml#ClusterMember_...)'
18|wsadmin>
表 3. 対話モードでの wsadmin セッションの説明
コメント
1wsadmin を開始し、言語として Jython を指定します。
2-4wsadmin によって生成された、デプロイメント・マネージャーへの接続成功を示す情報です。
5次の行をあまり長くしないように、ローカル変数に代入しています。
6新しいメンバーを作成するために、createClusterMember() メソッドを呼び出します。
7-16メソッドによって生成された、実行内容を説明する情報です (ここでは 12 行目は途中で切り捨てられています)。
17createClusterMember() メソッド呼び出しによって返された結果です (途中で切り捨てられています)。

このメソッドには、長所と短所の両方があるように見えます。

  • 最も重要な長所は、シンプルなインターフェースでしょう。3 つのパラメーターを使用するだけで、既存のクラスターに対して新しいメンバーを迅速かつ容易に作成できます。これらのパラメーターは、前出の AdminTask.createClusterMember() メソッドで必要なパラメーターとまったく同じです。
  • 短所に関して言えば、バナー・セクション (リスト 4、7 行目から 16 行目) の生成が目につき、うるさく感じる場合があります。これはスクリプト開発中は許容できますが、これらの行を無効にする簡単な方法はありません。これがこの方法を標準的に使わない理由になるのであれば、スクリプト・ライブラリーには別の利点があることを考慮してください。つまり、ソース・コードが用意されており、それをレビューできるのです。

ソースの利用

特定のメソッドのソース・コードは、比較的容易に検索することができます。ライブラリー・モジュールを使用する場合、このライブラリーが読み込まれたファイルを識別できるように、コマンドに __file__ 属性を追加できます。リスト 5 に、この属性の使用例を示します。

リスト 5. ライブラリーのソース・ファイルの検索
 1|...>wsadmin -lang jython -conntype none -c "print AdminClusterManagement.__file__"
 2|WASX7357I: By request, this scripting client is not connected to any server process.
 3|Certain configuration and application operations will be available in local mode.
 4|C:\IBM\WebSphere\AppServer70\scriptLibraries\servers\V70\AdminClusterManagement.py

もちろん、これらのスクリプト・ライブラリー・ファイルは直接変更しないでください。参照するライブラリー・ファイルのコピーを作成し、コピーのみを編集してください。

スクリプトのソース・コードを調べることで、次に挙げる事項など多くのことを学習できます。

  • パラメーター値を検証する方法。
  • どの WebSphere Application Server スクリプト・オブジェクトのメソッド呼び出しが使用できるか。
  • これらのスクリプト・オブジェクトのメソッドに対してパラメーターを指定する方法。
  • エラー・ハンドラーをセットアップする方法。

パラメーターのチェック

AdminClusterManagement.createClusterMember() メソッドをよく調べてみると、パラメーター値の検証方法がおおよそわかってきます。例えば、最初の 3 つのパラメーター (clusterName、nodeName、newMember) のどれにもデフォルト値が指定されていないため、関数を呼び出すたびに値を指定する必要があります。このことはコードを見直すと明らかです。メソッドに関する情報、およびメソッドがどのように呼び出されたかを表示するメソッドのバナーを除き、これらのパラメーターの値に、空文字列が含まれるかどうかがチェックされるからです。リスト 6 に、このコードの一部を示します (AdminUtilities._formatNLS() メソッドに指定されたパラメーターの内容は、エラーが検出されたパラメーター値を識別するために単に値を提供しているだけであり、パラメーターのチェックが実際にどのように行われるか理解するためには不要です)。

リスト 6. パラメーターのチェック
 1|# check  the required arguments
 2|if (clusterName == ""):
 3|  raise AttributeError(AdminUtilities._formatNLS(...))
 4|
 5|if (nodeName == ""):
 6|  raise AttributeError(AdminUtilities._formatNLS(...))
 7|
 8|if (newMember == ""):
 9|  raise AttributeError(AdminUtilities._formatNLS(...))
10|
11|# check if cluster exists
12|cluster = AdminConfig.getid("/ServerCluster:" +clusterName+"/")
13|if (len(cluster) == 0):
14|  raise AttributeError(AdminUtilities._formatNLS(...))
15|#endIf
16|
17|# check if node exists
18|node = AdminConfig.getid("/Node:"+nodeName+"/")
19|if (len(node) == 0):
20|  raise AttributeError(AdminUtilities._formatNLS(...))
21|#endIf

それぞれの環境に対してこれらのチェックは必要でしょうか、それとも十分なのでしょうか。それは各要件や、それを必要とする程度によって異なります。例えば、次のチェックは必要でしょうか。

  • None 値。
  • 文字列以外のデータ型。
  • 空白文字のみの値。

パラメーターにエラーがあると、スクリプト・ライブラリー・モジュールは ScriptLibraryException を生成します。生成したくない場合は、エラー検出時の動作を指定する必要があります。

コードは次に、指定された値が有効かどうかを判断します。ただし、リスト 6 に示したコードは改良の余地があります。例えば、2 行目は空文字列が指定されているかどうかを判断するためのチェックです。空白ではない場合、指定されたクラスターが存在するかどうかを 12 行目と 13 行目でチェックします。空白を 1 つ含む clusterName が指定されると、このコードで問題が発生します。2 行目の空文字列のチェックが false を返し、AdminConfig.getid( "/ServerCluster: /" ) メソッド呼び出しの結果は、全クラスターの構成 ID のリストになります。また、呼び出しの結果は空文字列にはならないので、13 行目のテストではエラーの検出に失敗します。

呼び出しの実行

パラメーターのチェックが完了したら、残りは AdminTask.createClusterMember() メソッドを実際に呼び出すことだけです。この呼び出しについては調べたばかりなので、ステートメントそのものは容易に理解できるはずです。

clusterMember = AdminTask.createClusterMember(['-clusterName', clusterName, '-memberConfig', ['-memberNode', nodeName, '-memberName', newMember]])

ご存知かもしれませんが、Jython wsadmin スクリプト・オブジェクトのメソッドは、文字列のリスト (ここで説明します) またはリストの文字列 (先ほど説明しました) を渡すことができます。この違いは構文にあります。上のステートメントをよく見てみると、個々の値はすべて、リテラル文字列 (単一引用符で囲まれたもの) または変数名であり、すべてカンマで区切られていることがわかります。これにより、変数の値を使用すべき場所で変数名 (clusterName、nodeName、newMember など) を使用できます。

Parameters = '[-clusterName ' + clusterName + ' –memberConfig [-memberNode ' + nodeName + ' –memberName ' + newMember + ']]’

このような文字列を連結した長いステートメントを使用したくない場合は、代わりに文字列フォーマット演算子を使用して、次のように表現できます。

FormatString % ( values )

文字列フォーマット演算では、FormatString の処理が必要になります。つまり、フォーマット指定シーケンスを探し、見つかったシーケンスを使用して、右のオペランドによって関連データをフォーマットします。フォーマット文字列内の他のテキストについては、そのデータはそのまま結果文字列にコピーされます。このシンプルな例では、文字列の置き換えを行う必要があることを示すため、FormatString 内に、フォーマット指定シーケンス %s を使用します。これらの文字 (フォーマット指定シーケンス %s) は、タプル (かっこで囲まれ、カンマで区切られた順序付きの値のシーケンス) 内にある、次の値の文字列表現によって置き換えられます。文字列連結の代わりに、文字列フォーマットを使用して、同じパラメーター文字列を構築するためには、次のようにします。

Parameters = '[-clusterName %s –memberConfig [-memberNode %s –memberName %s]]’ % ( clusterName, nodeName, newMember )

しかし、このような説明は予備知識にすぎません。何が可能になるかというと、実際のメソッド呼び出しを次のように簡略化できるのです。

memberID = AdminTask.createClusterMember( Parameters )

これこそが、作成しようとしているスクリプトの核心です。


テクニックの選択

スクリプトで実現したいタスクの遂行に使用可能な、さまざまなアプローチを調べてきましたが、いよいよ以下のどのメソッドを使用すべきかを決定する時が来ました。

  • AdminConfig.createClusterMember() メソッド。
  • AdminTask.createClusterMember() メソッド。
  • AdminClusterManagement.createClusterMember()scriptingLibrary メソッド。

最初のテクニックを選択した場合は、クラスターとノードの両方の構成 ID をメソッドで指定する必要があります。3 番目のテクニックを選択した場合は、メソッドの呼び出し時に scriptingLibrary バナーが表示されます。したがって、より良い選択肢は 2 番目のテクニックです。

一般に、特定の操作を実行するために AdminTask のメソッドと別のメソッドのどちらかを選ぶ場合、通常は AdminTask メソッドを選択した方が適切です。というのは、AdminTask のメソッドはスクリプト作成者に代わって多くの事を実行してくれるので、より堅牢なスクリプトをより簡単に作れるからです。

目的の操作を実施するために呼び出すべき実際のコマンド (またはメソッド) がわかったので、このコマンドを使用するスクリプトを作成できるようになりました。ただし、もう 1 つ決定しなければならないのが、どの程度に堅牢なスクリプトにする必要があるのかについてです。言い換えると、スクリプトでは最小限のチェックのみ行えばよいのか、またはすべてを徹底してチェック、検証しなければならないのかということです。この答えは、どれほどのリスクを容認できる (または容認する必要がある) かによって異なります。

最初にチェックできることの 1 つは、スクリプトが実行されたのか、インポートされたのかについてです。Jython でこれを確認するには、特別なグローバル変数である __name__ の値をチェックします。スクリプトが実行された場合、この変数の値は __main__ になります。インポートされた場合、この値はインポートされたファイルの名前になります。したがって、スクリプトが実行されたことを確認するため、リスト 7 に示すような簡単なテストをスクリプト・ファイルに含める必要があります。

リスト 7. スクリプトが実行されたかインポートされたかのチェック
 1|if ( __name__ == '__main__' ) :
 2|  # The script was executed
 3|else :
 4|  # The script was imported

ここで使用するアプローチでは、皆さんと一緒にスクリプトを構築するので、スクリプトで次に何を行うかは皆さんが決める必要があります。リスト 7. のコードに次の項目を追加して、スクリプトを続行してください。

  • スクリプトについて記述するコメント・ブロック (プロローグ)。
  • 実際に目的の作業を実施するコード用のプレースホルダーとする空の関数。
  • 書き込みを開始する必要のある Usage() 関数。

結果をリスト 8 に示します。

リスト 8. 反復 1
 1|#---------------------------------------------------------------------
 2|#       Name: createClusterMember.01.py
 3|#       Role: Example script, created from scratch.
 4|#     Author: Robert A. (Bob) Gibson
 5|#  Iteration: 1
 6|# What's new? Verify that the script was executed, not imported, and
 7|#             start populating the Usage information
 8|#---------------------------------------------------------------------
 9|import sys
10|
11|#---------------------------------------------------------------------
12|# Name: createClusterMember()
13|# Role: Placeholder for routine to perform the desired action
14|#---------------------------------------------------------------------
15|def createClusterMember() :
16|  print 'createClusterMember() - iteration 1'
17|
18|#---------------------------------------------------------------------
19|# Name: Usage()
20|# Role: Routine used to provide user with information necessary to
21|#       use the script.
22|#---------------------------------------------------------------------
23|def Usage( cmdName = None ) :
24|  if not cmdName :
25|    cmdName = 'createClusterMember'
26|
27|  print '''
28|Command: %(cmdName)s\n
29|Purpose: wsadmin script used to create an additional member to an
30|         existing cluster.\n
31|  Usage: %(cmdName)s [options]\n
32|Example: ./wsadmin.sh -lang jython -f %(cmdName)s.py ...''' % locals();
33|
34|#---------------------------------------------------------------------
35|# This is the point at which execution begins
36|#---------------------------------------------------------------------
37|if ( __name__ == '__main__' ) :
38|  createClusterMember();
39|else :
40|  print 'Error: this script must be executed, not imported.';
41|  Usage(__name__);

テストできるように、スクリプトを createClusterMember.py という名前で保存します (UNIX® にはシンボリック・リンク機能があり、そこではファイル名が現在の反復数を示すことができます。例えば createClusterMember.01.py となります)。

テスト結果をリスト 9 に示します。スクリプトが実行されたかインポートされたかを正しく判断したことが示され、OK を示すメッセージ (3 行目)、または使用法 (11 行目から 18 行目) が表示されます。

リスト 9. 反復 1 のテスト
 1|[root@ragdoll bin]# ./wsadmin.sh -lang jython -f createClusterMember.py
 2|WASX7209I: Connected to process "dmgr" ...
 3|createClusterMember() - iteration 1
 4|
 5|[root@ragdoll bin]# ./wsadmin.sh -lang jython
 6|WASX7209I: Connected to process "dmgr" ...
 7|
 8|wsadmin>import createClusterMember
 9|Error: this script must be executed, not imported.
10|
11|Command: createClusterMember
12|
13|Purpose: wsadmin script used to create an additional member to an
14|         existing cluster.
15|
16|  Usage: createClusterMember [optios]
17|
18|Example: ./wsadmin.sh -lang jython -f createClusterMember.py ...
19|wsadmin>

コマンドラインのパラメーターとオプションの処理

スクリプト作成における課題の 1 つは、コマンドライン・パラメーターの扱いです。よく使われるテクニックは、位置に依存したコマンドライン・パラメーターにすることです。つまり、最初のパラメーターは clusterName、2 番目のパラメーターは nodeName、3 番目のパラメーターは作成されるメンバーの名前、というように各位置のパラメーターが何を表すかを知っている必要があるということです。

Jython の本当の利点の 1 つは、ライブラリー・ルーチンが付属していることです。ライブラリーによって、より適切でユーザー・フレンドリーなスクリプトの作成が容易になります。このようなライブラリーとして getopt ライブラリーがあります。これは、かなり以前に C プログラミング言語に対してなされた成果 (C で書かれたプログラムからコマンドライン・パラメーターを容易に処理できるようになったこと) が基になっています。

getopt ライブラリーを使用するには、いくつかの作業を行う必要があります。まず、各パラメーター値に対して、短縮形のパラメーター文字と、長文形式のパラメーター名を選択する必要があります。短縮形 (1 文字) オプションを使用すると、スクリプトを次のように実行できます。

... –f createCluseterMember.py –X clusterName –Y nodeName –Z memberName

上のコマンドでは、X、Y、Z はプレースホルダーとして使用しています。コマンド内でパラメーターの識別に役立つ使いやすい文字を指定してください。例えば、clusterName には -c、nodeName には -n、memberName には -m とします。ただし、この場合、-c は使用できません。-c は wsadmin ユーティリティ用に予約されたコマンドライン・オプションなので、スクリプトでは使用できません。代わりに、短縮形コマンドライン・オプションとして -L を使用して、clusterName パラメーター値を指定します (大文字を使用して、数字の 1 との混同を避けます)。

次に、これらのオプションを検索するように getopt ユーティリティ・ルーチンに指示する必要があります。これには、次を実行します。

  1. getopt ライブラリー・モジュールをインポートします。
  2. getopt.getopt() 関数を呼び出し、必須パラメーターを渡します。

getopt() 関数には次のパラメーターが必須です。

  • ユーザー指定のコマンドライン・パラメーターのリスト。
  • 短縮形のオプションを識別する文字列。
  • 長文形式のオプションを含むリスト。

短縮形の文字列には、有効な各オプション文字と、その後にコロン (:) を含める必要があります。コロンは、コマンドライン・オプションの後に値があることを示しています。getopt ライブラリー・ルーチンは、一般に汎用性がありますが、すべてのコマンドライン・オプションが値を持つと想定されているわけではないことに注意してください。値を必要としないコマンドライン・オプションが必要となる状況を考えてみてください (例えば、デバッグを有効にしたい場合など)。これを示すには、「-X」のようなオプション・パラメーターが非常によく使用されます。

このことがどのように意味をなすか理解できたことと思います。このケースでは、3 つの短縮形のオプション文字を持ち、それぞれの後に値が続く必要があることを決定しています。shortForm のオプション文字列は次のようになります。

shortForm = 'L:m:n:';

この例では、文字列内にオプション文字が存在するか、それぞれが値を持つかどうかを getopt 関数にチェックさせる必要があります。これらのパラメーターの出現順序を定義するために特別なことをする必要はありません。また、各オプションの出現回数を示すために getopt() 関数に渡す文字列で特別なことをする必要もありません。これがスクリプトにとって意味があるかどうかを判断する方法はすぐにわかります。

さて、長文形式のコマンドライン・オプションの場合はどうでしょうか。短縮形のコマンドライン・オプションはそれぞれ 1 つの文字とその前の 1 つのハイフン (-) で表されることを思い出してください。長文形式のコマンドライン・オプションの形式は似ていますが、少し異なります。すべての長文形式のオプションは 2 つのハイフン (--) で始まり、可変数の英数字で表されます。この例では、次のような長文形式のオプション ID を使うとわかりやすくなります。

  • clusterName
  • nodeName
  • memberName

これらの各オプションの後に値が続くことを getopt() 関数に示すことも必要です。そのためには、文字列値のリストを使用します。各文字列はオプション ID で、その後に等号を付けます。この例の longForm オプションは次のようになります。

longForm = [ ‘clusterName=’, ‘nodeName=’, ‘memberName=’ ];

これとは別の、同一の式を表すより簡潔な方法は、次のような代入ステートメントを使用することです。

longForm = 'clusterName=,memberName=,nodeName='.split( ',' );

ここで、split() は、指定された区切り文字 (この場合はコンマ) を含む (文字列型の) 入力文字列を処理して、文字列のリストを返すメソッドです。したがって、上の 2 つの代入ステートメントは、どちらも同じ文字列値のリストを生成します。読みやすく、理解しやすいと思う方を使用してください。

最終的に、getopt ルーチンの実際の呼び出しは次のようになります。

getopt.getopt( sys.argv, shortForm, longForm );

かなり洗練されましたが、実際にどのオプションが検出されたかは、どのように伝えられるのでしょうか。答えは、関数から返される次の 2 つです。

  • 有効なオプションの名前と値のペアのリスト。
  • 残っている (未処理の) オプションのリスト。

リスト 10 に、この状況をコードでどのように処理するかを示します。

リスト 10. getopt() 関数の使用
 1|try :
 2|  opts, args = getopt.getopt( sys.argv, shortForm, longForm );
 3|except getopt.GetoptError :
 4|  # code to handle the exception situation
 5|
 6|for name, value in opts :
 7|  # code to handle each value option letter/identifier
 8|
 9|if ( args != [] ) :
10|  # code to handle “extra” stuff on the command line

コードが省略されている部分 (4、7、10 行目) 以外は、かなり簡単に見えます。

  • 認識されないオプションが検出された場合や、オプションに必須の値が含まれない場合は、getopt() 関数によって例外がスローされます。例外ハンドラーのコード (4 行目) で適切なメッセージを表示し、スクリプトを終了する必要があります。
  • for ループ内のコード (7 行目) は、サポートされる各オプションを処理する場所です。ここで、コマンドライン・オプションが複数回出現したかどうかについて、それが重要であればチェックします。
  • 最後のセクション (10 行目) では、有効なオプションと関連付けられていない余分な情報が指定されていないかをチェックし、処理することができます。

この情報は、リスト 11 に示す parseOpts() ルーチンを理解するために役立ちます。このルーチンを呼び出すと、ユーザー指定のコマンドライン・オプションを示す辞書が返されます。

リスト 11. 完全な parseOpts() ルーチン
 1|#---------------------------------------------------------------------
 2|#    Name: parseOpts()
 3|#    Role: Process the user specified (command line) options
 4|# Returns: A dictionary containing the user specified values
 5|#---------------------------------------------------------------------
 6|def parseOpts( cmdName ) :
 7|  shortForm = 'L:m:n:';
 8|  longForm  = 'clusterName=,memberName=,nodeName='.split( ',' );
 9|  badOpt    = '%(cmdName)s: Unknown/unrecognized parameter%(plural)s: %(argStr)s';
10|  optErr    = '%(cmdName)s: Error encountered processing: %(argStr)s';
11|
12|  try :
13|    opts, args = getopt.getopt( sys.argv, shortForm, longForm );
14|  except getopt.GetoptError :
15|    argStr = ' '.join( sys.argv );
16|    print optErr % locals();
17|    Usage( cmdName );
18|
19|  #-------------------------------------------------------------------
20|  # Initialize the Opts dictionary using the longForm key identifiers
21|  #-------------------------------------------------------------------
22|  Opts = {};
23|  for name in longForm :
24|    if name[ -1 ] == '=' :
25|      name = name[ :-1 ]
26|    Opts[ name ] = None;
27|
28|  #-------------------------------------------------------------------
29|  # Process the list of options returned by getopt()
30|  #-------------------------------------------------------------------
31|  for opt, val in opts :
32|    if opt in   ( '-L', '--clusterName' ) : Opts[ 'clusterName' ] = val
33|    elif opt in ( '-m', '--memberName' )  : Opts[ 'memberName' ] = val
34|    elif opt in ( '-n', '--nodeName' )    : Opts[ 'nodeName' ] = val
35|
36|  #-------------------------------------------------------------------
37|  # Check for unhandled/unrecognized options
38|  #-------------------------------------------------------------------
39|  if ( args != [] ) :        # If any unhandled parms exist => error
40|    argStr = ' '.join( args );
41|    plural = '';
42|    if ( len( args ) > 1 ) : plural = 's';
43|    print badOpt % locals();
44|    Usage( cmdName );
45| 
46|  #-------------------------------------------------------------------
47|  # Return a dictionary of the user specified command line options
48|  #-------------------------------------------------------------------
49|  return Opts;

上の parseOpts() ルーチンを含む完全なスクリプトは、ダウンロード資料に含まれる createClusterMember.02.py ファイルに入っています。


コマンドライン・オプションの検証と使用

この時点で、ユーザー指定のコマンドライン・パラメーターをチェックし、結果を辞書で返すスマートな関数ができました。それでは、今度はその関数で何をするのでしょうか。

最初に、parseOpts() 関数は、エラー条件が検出されない場合のみ、辞書として結果を返すことを確認してください。つまり、parseOpts() ルーチンがチェックした条件に関して、問題が検出されなかったということです。しかしこれは、必ずしも何の問題も存在しないということを意味するのではありません。

リスト 12 に、このスクリプトの 2 回目の反復によって、これらのパラメーターがどのように処理されるのかを示します。

リスト 12. 反復 2: parseOpts() ルーチンの呼び出し
 1|missingParms = '%(cmdName)s: Insufficient parameters provided.';
 2|
 3|#-------------------------------------------------------------------
 4|# How many user command line parameters were specified?
 5|#-------------------------------------------------------------------
 6|argc = len( sys.argv );                   # Number of arguments
 7|if ( argc < 3 ) :                         # If too few are present,
 8|  print missingParms % locals();          #   tell the user, and
 9|  Usage( cmdName );                       #   provide the Usage info
10|else :                                    # otherwise
11|  Opts = parseOpts( cmdName );            #   parse the command line

リスト 12 のコードは、parseOpts() ルーチンがどのようにして、3 つ以上のパラメーターが指定された場合にのみ呼び出されるかを示しています。getopt() ルーチンによって処理されるパラメーターの最小個数は 3 つで、以下に示します。

[ ‘-LclusterName’, ‘-nNodeName’, ‘-mMemberName’ ]

8 行目の print ステートメントは、前述の文字列フォーマット演算の別の例です。ここでの違いは、フォーマット文字列は、それぞれのフォーマット指定で、置き換えのために使用する辞書のエントリーを特定する必要があることです。したがって、%(cmdName)s を含むフォーマット文字列は cmdName というローカル変数で置き換えられ、値は文字列として表示されます。

これは、Usage() ルーチンでも使用されている、非常に強力な表現形式です。例えば、リスト 8 の 27 行目から 32 行目を見ると、別のマップされたメッセージが見つかります。この例のフォーマット文字列で興味深い点は、同じローカル変数 (cmdName) が同じ文字列内に複数回出現することです。

parseOpts() ルーチンから返される辞書で何ができるでしょうか。対応する索引を使って個々の辞書値にアクセスすることもできますが、辞書値をローカル変数に代入すると、はるかに使いやすくなります。リスト 13 の 2 つのステートメントを比較すると、どちらがシンプルで理解しやすいかがわかります。

リスト 13. 読みやすく、理解しやすいのはどちらか
 1|if  ( not Opts[ ‘clusterName’ ] ) :
 2|  print ‘Required option missing: clusterName’
 3|
 4|if ( not clusterName ) :
 5|  print ‘Required option missing: clusterName’

parseOpts() ルーチンから返される辞書を対応するローカル変数に簡単に変換する方法は、一連の代入ステートメントを使用することです (リスト 14)。

リスト 14. 辞書エントリーからローカル変数への単純変換
 1|clusterName = Opts[ ‘clusterName’ ];
 2|nodeName    = Opts[ ‘nodeName’ ];
 3|memberName  = Opts[ ‘memberName’ ];

有効なコマンドライン (長文形式) ID の数が少ない場合は、このアプローチで問題ありません。しかし、リスト 15 に示すように、辞書内に存在する ID を使用した別の方法があります。

リスト 15. 辞書エントリーからローカル変数への汎用変換
 1|#-------------------------------------------------------------------
 2|# Assign values from the user Options dictionary, to make value
 3|# access simplier, and easier.  For example, instead of using:
 4|#   Opts[ 'clusterName' ]
 5|# we will be able to simply use:
 6|#   clusterName
 7|# to access the value.  Additionally, this allows us to make use of
 8|# mapped error messages that reference local variable values.
 9|#-------------------------------------------------------------------
10|for key in Opts.keys() :
11|  cmd = '%s=Opts["%s"]' % ( key, key );
12|  exec( cmd );

このコード・セグメントのカギは、作成される文字列 (リスト 14 の代入ステートメントによく似ています) と、代入ステートメントを実行して実際の変数への代入を行う exec() ルーチンです。

この時点では、スクリプトのこの反復で行うことは、ユーザー指定の値を示すメッセージの表示だけです。このバージョンのスクリプトを使用すると、期待されていることをコマンドラインの処理で行っていることをテストし、確認できます。


目的とする操作の実行

残っているのは、ユーザー指定の値をチェックするコードを追加し、これらの値を使用して目的の操作を実行することだけです。

必須値の 1 つが None の場合、これはいずれかのコマンドライン・オプションが指定されなかったことを意味します。これはどうして起きるのでしょうか。parseOpts() 関数内でコマンドライン・パラメーターを処理するコードは、重複についてチェックしません。したがって、ユーザーが次のようなコマンドライン・パラメーターを指定するとどうなるでしょうか。

--clusterName=C1 -L C2 -L C3

結果は、nodeName オプションと memberName オプションの値が、どちらも None になります。parseOpts() 関数を変更して、同じコマンドライン・オプションが複数回出現したかどうかをチェックすることもできますが、このような種類のチェックの追加が、どれほど重要かを判断する必要があります。

また、空の文字列値についてのチェックも検討する場合があります。空白の値は、二重引用符で囲んで指定できます。

./wsadmin.sh -f createClusterMember.py -L " " -n " " -m " "

2 つめの例をスクリプトでテストすると、出力は次のようになります。

createClusterMember: --clusterName --nodeName --memberName

すべての値が必須なので、各値に対して同じチェックを実行する必要があります (さらにチェックを追加して、指定した clusterName と nodeName が既に存在すること、および指定した memberName が存在しないことを確認することもできます。これらのチェックについてはこの記事で説明しませんが、これらのチェックを実行する価値があると判断した場合は、いつでも後から追加できます)。

もう 1 つ認識する必要があるのは、Opts 辞書からローカル変数を作成するために使用するループと同じループに対し、チェックを追加できることです。リスト 16 に、この修正を加えたコードを示します。

リスト 16. 無効な必須値に対するチェックの追加
 1|badReqdParam = '%(cmdName)s: Invalid required parameter: %(key)s.\n';
 2|
 3|#-------------------------------------------------------------------
 4|# Assign values from the user Options dictionary, to make value
 5|# access simplier, and easier.  For example, instead of using:
 6|#   Opts[ 'clusterName' ]
 7|# we will be able to simply use:
 8|#   clusterName
 9|# to access the value.  Additionally, this allows us to make use of
10|# mapped error messages that reference local variable values.
11|#-------------------------------------------------------------------
12|for key in Opts.keys() :
13|  val = Opts[ key ];
14|  if ( not val ) or ( not val.strip() ) :
15|    print badReqdParam % locals();
16|    Usage();
17|  cmd = '%s=Opts["%s"]' % ( key, key );
18|  exec( cmd );

リスト 16 の 1 行目に、値が None (または空文字列) の場合に表示される、新しいマップされたエラー・メッセージの作成を示します。指定した ID の値を取得する 13 行目から 16 行目が修正されています。

14 行目の式の最初の部分は、None 値のチェックに使用されます。変数 val の値が None である場合は、( not val ) の結果が true になり、エラー・メッセージが表示されます。式の残りの部分は、値 (先頭または末尾の空白を除いたもの) が空文字列かどうかを確認するために使用されます。空文字列の場合は、エラー・メッセージが表示され、Usage() ルーチンが呼び出されて、スクリプトは終了します。


AdminTask.createClusterMember() の呼び出し

ユーザーがすべての必須パラメーターの値を指定していることを確認したので、残りは AdminTask.createClusterMember() メソッドの呼び出しの中で、それらを使用することだけです。メソッド用のパラメーター文字列を構築する方法については前に見てきたので、準備はすべて整ったように思われます。

たしかに、ほとんど整いました。最後に、スクリプトがエラーから保護されていることを確認してください。メソッド呼び出しが失敗すると、例外がスローされるようにします。リスト 17 に、実際の AdminTask.createClusterMember() メソッドを呼び出すスクリプトの一部を示します。

リスト 17. AdminTask.createClusterMember() の呼び出し
 1|#-------------------------------------------------------------------
 2|# Call the AdminTask.createClusterMember() method using the command
 3|# line parameter values.
 4|#-------------------------------------------------------------------
 5|parms = '%(cmdName)s --clusterName %(clusterName)s --nodeName %(nodeName)s
   --memberName %(memberName)s';
 6|print parms % locals();
 7|try :
 8|  Parms = '[-clusterName %s -memberConfig [-memberNode %s -memberName %s]]' %
   ( clusterName, nodeName, memberName )
 9|  AdminTask.createClusterMember( Parms );
10|  AdminConfig.save();
11|  print '%(cmdName)s success. Member %(memberName)s created successfully.' % locals();
12|except :
13|  #-----------------------------------------------------------------
14|  # An exception occurred. Convert the exception value to a string
15|  # using the backtic operator, then look for the presence of a
16|  # WebSphere message, which start with 'ADMG'.  If one is found,
17|  # only display the last part of the value string.
18|  #-----------------------------------------------------------------
19|  val = `sys.exc_info()[ 1 ]`;
20|  pos = val.rfind( 'ADMG' )
21|  if pos > -1 :
22|    val = val[ pos: ]
23|  print '%(cmdName)s Error. %(val)s' % locals();

表 4 は、リスト 17 に示したコード・セグメントの説明です。コードが何をしようとしているか、そのジョブにどのように取り掛かるかを理解するために役立ちます。

表 4. AdminTask.createClusterMember() の呼び出しの説明
コメント
1-4実行する操作を明示するコメント・ブロックです。
5実行されている操作、およびユーザー指定の値を表示するために使用する、マップされたメッセージです。
6ローカル変数値を使用したマップされたメッセージを表示します。
7-23例外ハンドラー (例えば、try/except ブロックなど) で保護された createClusterMember() メソッドを呼び出します。
8メソッドのパラメーター文字列の構築に使用する、マップされたフォーマット対象文字列です。
9createClusterMember() メソッドの実際の呼び出しです。
10createClusterMember() が成功した場合は、修正された構成を保存するために AdminConfig.save() を呼び出します。
11要求されたアクションの成功を示すメッセージを表示します。
12-18例外が発生した場合、最も失敗した可能性が高いステートメントは createClusterMember() ルーチンの呼び出しです。
19何が起きたかを確認するために sys.exc_info() を呼び出します。実のところ、このインスタンスでは 2 番目の値 (エラー値) だけが重要なので、それだけを保存します。戻り値を文字列に変換するには、backtic 演算子を使用します。
20文字列内で最後に出現する ADMG のメッセージ番号プレフィックスを見つけるために rfind() を呼び出します。
21-22メッセージ・プレフィックスが存在する場合は、その前にある文字をすべて廃棄し、例外によって生成された重要なエラー・メッセージのみを保持します。
23エラー・メッセージのテキストを表示します。

まとめ

この記事では、特定の IBM WebSphere Application Server の管理タスク (この場合は、既存のクラスターへの追加メンバーの作成) を実行するために、wsadmin Jython スクリプトを作成するアプローチを紹介しました。インフォメーション・センターのドキュメントを使用して、タスク遂行に関するさまざまなオプションを学習する方法、およびオプションを比較して最も実用的なアプローチを決定する方法について説明し、管理可能な段階を踏んでサンプル・スクリプトを作成するステップを見てきました。この記事では、一般的な注意事項、より適切なプラクティス、スクリプトのテスト方法、およびエラー条件の処理方法も示しました。

この情報が有用で貴重なものだと思っていただけることを期待します。

著者による書籍:『WebSphere Application Server Administration Using Jython
『WebSphere Application Server Administration Using Jython』

ダウンロード

内容ファイル名サイズ
Sample scriptscreateClusterMember.scripts.zip16 KB

参考文献

学ぶために

製品や技術を入手するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=WebSphere
ArticleID=605266
ArticleTitle=ゼロからのスクリプト作成: Jython による IBM WebSphere Application Server 向けの管理スクリプトの作成
publish-date=04072010