きどたかのブログ

いつか誰かがこのブログからトラブルを解決しますように。

gradleを1日だけ見て感じたこと

なんかピンとこない。
何がピンとこない?

何がどう作用するのか読み解けない。
それはJSONなのか、
クラスなのか、クロージャなのか。
構文的な、シンタックス的な、
DSLが直感的に読み解けない。


1日程度見ただけで分かるというのは虫の良い話だろうか。


taskのdoLastやdoFirstがなぜ呼ばれるのか。
テンプレートなんだろうなぁ。
関数登録してるんやろうなぁ。


基本Javaばかり書いてるけど
Jythonを相当書いてるので、軽量言語もわからなくもない。
Goはやや特殊なところがあり、理解するのに2-3日かかった。
さて、groovyはどうかと眺めてみると、
なにも苦痛を感じない。Jythonとそこまで遠くない。


なので、gradleのDSLな部分?が苦痛を与えているという理解に至った。


apply pluginはなにをやっているのだろうか。
関数の読み込みであったり、フィールドの追加であろう。
たった一行なので、なにがどれだけ追加されたのか読み解けないってだけ。


taskの宣言は、なんかJavaのインナークラスっぽく感じるところがある。そう感じるのは、変数スコープがちょっと分かりにくいと感じているせいでもあろう。


build.gradleはおそらく1つのクラスで、
apply pluginすることで、関数・タスクだとかフィールドが追加されて、task宣言するとインナークラスができて、アウターの関数・フィールドも使える、そんなイメージかなぁ。


少しマニュアルを読み進めた(かいつまんで)。
カスタムプラグインの作り方を見て、
apply pluginのやってそうなことの理解が進んだ。
build.gradle自体はProjectという型なんだな。


JSONっぽい書き方で、階層の最後の方でいきなり関数かよってところがとっつきにくい。
実は全部クロージャなの?的な迷い方をする。
ブロック?
Goのレシーバっぽいところでもあるのかな。


個々のクラスやプラグインの内容をしっかり読めば、たぶんそのあたりは解消できるんでしょう。

PowerShellでInstallation Managerをインストールしてみたかったんだが

まだできてない。

UACが邪魔すぎる。
ConsentPromptBehaviorAdminで詰まる感じだろうか。


Start-Processに-Verb runasを付けているので、
installc.exeは管理者権限で動こうとしているが、プロンプトが邪魔になり完全自動にならない。
コンピュータへの変更の許可を求められてしまう。昇格するかのプロンプトは乗り越えてるはずなんだけど。


UAC周りのレジストリを書き換えるにも権限が必要になるので厳しい。


Start-Processでpowershellを管理者権限で動かしてからinstallc.exeを叩かせるのは試していないんで今度やってみる。


すでにInstallation Managerがインストールされていると、既存のインストールディレクトリなどを検証されてしまうので、そこはレジストリから値を抜いて更新インストールになるようにパスを合わせるコードは書けて、プロンプトさえ超えれば動くことが確認できた。


この辺りのことができるようになってしまえば、Windows環境でいろいろなものを自動インストールできるんだよなぁ。



引数にdict,tuple,list,java.util.Propertiesを受け付ける関数の検討

タイプの判定をやってみた。
引数は最終的にdictionaryに詰め込む。

import typesして
if types.DictType==type(arg):
 self.mydictionary.update(arg)
#endif
みたいなことをしてみた。
tupleとlistも似た判定に加えて、要素が2であるチェックをして、key:valueで詰め込む。


割と悩んだのが、java.util.Propertiesの判定だった。
まずfrom java.util import Propertiesしとく。
if isinstance(arg,Properties):
こんな感じでいけるようだった。
まあ、たぶん使わないんだが、興味本位で考えてしまった。


props=Properties()
print type(props)
これで検査すると、org.python.core.PyJavaInstanceが出てきてしまい、typesモジュールで判定は難しいように思えた。
PyJavaInstanceだったか、他の何かにはclass属性があるので、それを判定に使おうかとも考えたけれど、違和感があるので踏みとどまった。


関数の引数を工夫するのも考えたんだけど、
あれは少し慣れが必要だし、今回はPropertiesも受け付けるのも考えてたんで遠慮した。
普通にやるなら辞書のみでやればいい。


今日失敗に気付いた有効範囲ノードのリソース

すごく単純な失敗をしていたことに気付いた。


ノードのJMSプロバイダーを使い、
接続ファクトリーを作成するコードだったのだが、誤ってサーバにも作ってしまっていた。


node_scope=AdminConfig.getid('/Node:mynode')
jms_provider_list=AdminConfig.list('JMSProvider',node_scope).split('¥n')
ここから先もあるんだが、この時点でNG。
ノードだけでなく、サーバのJMSProviderも拾っている。
念のため補足しとくと、接続ファクトリを作るにはJMSProviderの構成IDが必要になるから、それを拾ってこようとしている。


AdminConfig.list(type,scope)を使うのに慣れているのに、AdminConfig.list(type,pattern)を書かないといけなくなった。
名前が固定で、存在しないことは考えられないから、ループで検査しなくても、名前ダイレクトにJMSProviderをgetidしてもいいかもしれないなぁ。


wsadminでImportError レアもの?

すごい面倒臭いエラーに出くわした。


ImportErrorがなかなか取り除けなかった。
凡ミスもあった。
__init__.pyをミペルミスしてて、
__ini__.pyになってた。
これはいい。


今回ドハマりしたのは、もっと気づきにくい話。


ImportErrorなんだから、探索パスを気にした。
sys.pathを出力。
あるある、ちゃんとある。
でも見つからない。
__init__.pyは修正済み。



wsadmin.shを叩くときには、-javaoption "-Dwsadmin.script.libraries.packages=/どこそこ:/あそこ:/こっち" -f わたしの.py を渡している。
それがsys.pathにも反映されている。


実際のフォルダは、こんなかんじ。
a/b/c.py
a/b/d/e.py
a/f/g.py


wsadmin.shに-fで渡してるのがc.pyな感じ。
e.pyはg.pyに書いてるクラスをインポートしている。
from a.f.g import Hoge, Foo


どんなに頑張っても、eモジュールが見つからない。
e.pyの例のimportは、これから先に使うつもりで、まだ使っていなくて、消してみたら、e.pyが見つかるようになった。


なんじゃそりゃ!!

もっかい構成を詳細に書いておく。
c.pyがg.pyにあるクラスをインスタンス化して、e.pyにある関数をg.pyのクラスのインスタンスに関数のまま渡して、c.pyがインスタンスをキックすると、最終的に関数が呼ばれる構成。
言葉で書くと分かりにくい。。。


真の原因は自分には分からないが、
クラスをインポートしてるモジュールは、見つからなくなる、って解釈になる。ざっくりすぎだが、症状としてはそうなる。
python的なパスと、Java的なパスがごちゃごちゃしたのか??


こんなことで半日潰れた。
解決の糸口を見つけただけ良かったと思おう。
まだ終わってない。自分が考えた設計の障害になっている。きっと乗り越えてやるよ。



jythonスクリプトの日々

ファイアウォールのカスタムルール用ファイルを作成するjythonスクリプト、凡ミスしてたがなんとか直した。


DNSがいないせいもあり、/etc/hostsに書き込まないとdmgr起動しないのは大変だった。
DCSとか出てたからファイアウォールをミスったのかと自己暗示にかかった。


最終的にはファイアウォール設定にこぎつけた。

ls /etc/sysconfig/ipv4_filter_addon_was_* | xargs -i lokkit --update --custom-rules=ipv4:filter:"{}"

jythonでファイルを作ってあげるときは、-connType NONEで構わない。AdminConfigしか使ってないので、Dmgr01プロファイルでやれば問題ない。


その他、グローバルセキュリティのユーザーレジストリをローカルOSに変えたり、
sdkを7にしたり、
J2C認証エントリを作ったり。。。


すごいゴミだらけの昔の設定を見ながら、
新しく作る環境を全部スクリプトで書く。


相変わらずJDBCプロバイダーの作成は面倒臭い。
pdqないから、クラスパスから削ったのに、管理コンソールのコマンドアシスタントは、削ったものをぶちこんできた気がする。戻るボタンでも押してたっけな。。。
あと、ユニバーサルドライバーパスもWebSphere変数にされてるのだから、入力項目を画面にだしてほしいもんだ。サーバースコープだとダメなんか?
それはそれとして、結局WebSphere変数を設定するコマンドアシスタントはでてこないので、別途書く必要がある。
variableMapからエントリ探すコードは面倒臭いんだよ、書けるけどさ。


SDKを変えるのは、次のコマンドを使うことにした。
AdminTask.setNodeDefaultSDK()
オプションの-clearServerSDKsの挙動を見ておきたい。きっとクリアするだけじゃなく、ちゃんと新しいのに設定してくれるよね。
ノード名は、AdminConfig.list('Node')して、スプリットして、ループさせて、ごにょごにょ。
オプションの-sdkNameを使うつもりだが、値はまだベタ書き。
AdminTask.getSDKVersion()にオプション-highestを付けて、どんな文字列が返ってくるかで、そこもベタ書きをやめられる気がしている。


いま書いてるスクリプトは、汎用性に欠ける。
ただの関数だけでは変更に弱いというか、見通しが悪い。
クラスにしたい。
visitorパターンとか使えないかな。
ベースとなるトポロジ、特にセル名、ノード名があり、そこから追加するトポロジ(クラスター、サーバー)があり、個々のスコープで行うことを書く。
トポロジ側にacceptを書いてくイメージかな。


def accept(self,variablevisitor):
  variablevisitor.visitCell(self.getCellName())
  for node_name in self.getNodeNames():
    variablevisitor.visitNode(node_name)
  #endfor
 ...
#enddef


全てのノードに同じ設定をするならいいけど、バラついた設定にしたい時には厳しいかなぁ。でも、コードからトポロジを分離できる方が嬉しいんだよな。


んー、ダメだ。これは破綻する。
とくにクラスタで破綻する。
クラスタは大抵用途が違ってくるので同一設定とかありえない。


トポロジー分離は残しつつ、別の方法を模索。
topology = Topology()
topology.addProperty(('hoge_path','/opt/hoge')
cell=topology.addCell('mycell')
cell.register(func_mycell_decorator)
dmnode=cell.addDMNode('mydmnode')
mynode1=cell.addNode('mynode1')
mynode1.register(func_mynode1_decorator)
myserver1=mynode1.addServer('myserver1')
myserver1.register(func_myserver1_decorator)
topology.build()

トポロジ、セル、ノード、サーバ、クラスタは、クラスにする。
配下を作成(add)するときに、Topologyは伝播させて保持させる、セルはノードとクラスタも保持、ノードはサーバを保持。(利用するシナリオはなかなか思いつかないけど)
これらのクラスはデコレーターパターンっぽい扱いだが、デコレーションの仕方は、パッケージを工夫して関数登録にする。たぶん出来るはず。
プロパティーを個々のクラスが持てるようにする、使うか使わないかは関数次第。
個々のクラスのプロパティーにない場合、トポロジのプロパティーを見るようにする。
プロパティーはほとんどWebSphere変数の用途だが、だからといって一つ上のスコープを探すのはちょっと違うだろう。クラスタならまだしもノンクラスタで、一つ一つのサーバーに登録するのが面倒な値だとか、本当ならノードごとに違うかもしれんが、同一ホストの複数ノードみたいな垂直っぽいときに、同一ホストのファイルパス変わるわけないみたいなのを二回書くのが嫌だなって思ってのことです。


デコレーションを関数にしているので、
メイン実行できるようにもしておく。
例えば、サーバに登録する関数は、サーバクラスからサーバ自身を受け取るが、ノード名とサーバ名を取り出してすぐに他の関数コールする想定。なんかこれ考えてる段階ですでに設計バクしてそうな予感は漂ってきている、クラスに登録しといたプロパティーが渡せてなーい。ま、一旦置いておこう。どの種類の引数使うかも悩んでるところやし。
if __name__ ==__main__の判定ののち、引数解析して単独実行(他の関数のほうを呼ぶ)もできるようにしておく。単独とはいいつつも、きっと1ファイルでは動かないんだけどな。


このデザインにも課題がある。
ノード内サーバへの一括登録や、クラスタメンバへの一括登録は、サーバの設定よりも優先すべきか否か、順序の問題がある。


それと、クラスタの作成順序もある。
1つ目のメンバのコピーを2つ目のメンバにしたいというなら、先にサーバ設定を仕上げておかないと嬉しくない。ああ、でも、後から追加でもいいのかな。後からと言ってる時点、やっぱり順序を意識してるじゃないか。


パッケージのイメージ。
ショートホスト名.cell
ショートホスト名.cell.node1
ショートホスト名.cell.node1.server1
ショートホスト名.cell.cluster1
ホスト跨ぐ水平クラスタになると破綻するじゃないか。
やっぱり、セル名でいくしかないかな。
同一のセル名がでてくると困るんだよね。
んー、やはりショートホスト名でいく、dmgrがいるところのショートホスト名だ。
ホスト名同じでIP違うとかはしらん。


ほかに考えることは、ログとsave()タイミング。
バージョン的に使えるのなら、loggingを使う。
pythonにはある。WAS付属のjythonバージョン次第、けっこうギリギリのラインだった気がする。
AdminConfig.save()を細かくやるか、スコープでやるかみたいなストラテジを入れたいところ。それやると、引数が多くなりそうで嬉しくはない。コードの中の色んなところに判定が必要になって汚くなりそう。


wsadminlib.pyは知ってるし、使ったこともあるが、書いてるコードが構造的にエクセレントになるわけではない。もちろん雑多なコードを省略できることは確かなんだが、どこに何を設定しているかを分かりやすくするには別の取り組みが必要だと考える。


日を跨いで、、、上記のようなデコレーターパターンっぽいコードは実際に動作するように組み立てることはできた。
だが、書き進めてるうちに別の問題が。
続きは別のエントリで。

zWASっぽくプロファイルを作る試み

zWASは、プロファイルのディレクトリ構成がLUWのものと違う。


LUWの場合
/opt/IBM/WebSphere/AppServer/profiles/Dmgr01
/opt/IBM/WebSphere/AppServer/profiles/AppSrv01


z/OSの場合
/wasv85config/セル名/デプロイメントマネージャーノード名/DeploymentManager/profiles/default
/wasv85config/セル名/サーバーノード名/AppServer/profiles/default


z/OSの方が命名規則などが厳しいので、LUWでz/OSっぽく作る方法はないかを考えた。


一番のハマるポイントは、プロファイル名だろう。
zWASの場合、プロファイル名はdefault以外使えないはずで、それをLUWで真似ようとすると、プロファイル名の重複で死亡する。


プロファイル名とプロファイルパスは別物で、
プロファイルパスをzWASっぽくするだけで構わない。プロファイル名はDmgr01とAppSrv01のまま。


解決できなかった問題はある。
profileTemplateからセルプロファイルを作ると、サーバー名を変更できない。
dmgrとnodeagentはちょっとキツイ。
server1は消して作れば命名規則をzWASのものにできるだろう。
セル名とノード名はプロファイル作成時に命名規則を合わせられる。


manageprofiles.shでdmgrを作るときに、本来なら受け付けるべきではない-serverNameオプションを渡したら、作れるは作れたが、startManager.shで起動できなかった。


dmgrとnodeagentは諦めとく。
zWAS側の構成で、ロングネーム、ショートネームをカスタマイズしとくと、ロングネームでLUWと合わせることはできたはずだけど、そっちを変更するのが面倒臭い。


セル名やノード名を合わせられることで、AdminConfigを使っての設定は、ほとんど同じにできるだろう。もちろんプロセス定義の箇所は難しい。
jython書いてると、ほとんどファイルパスを使うことはない。思い付くところでは、JDBCプロバイダー、JMSプロバイダー、共用ライブラリ、JVMのオプションファイルとか。
プロファイルパスの下に置かないといけないものはない。
ファイルパスよりも、トポロジーを合わせることの方が意味がある。


zWASっぽい方は、マウントしやすい。
LUW的構成で、プロファイルを作る前に、存在しないパスにマウントするのは不可能で、それを実現しようとmkdirで先にプロファイルのディレクトリを作ってしまうと、manageprofiles.shが失敗するだろう、既にあるプロファイルだということで。