きどたかのブログ

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

IBM Data Studio 4.1.1にWebsphere Developer Tools for Junoを入れたい

今となっては、SQLJ開発を無償ツールでやるには、IBM Data Studioが大本命だろう。


しかし、私として、そこにWAS用のプラグインは入れたい。


IBM Data StudioはEclipseのバージョンが古いが、仕方ないのでJunoベースでなんとかしよう。


素のIBM Data Studio 4.1.1に、Websphere Developer Tools for Junoを入れようとしても、依存ライブラリが足らない。


Juno自身の更新が必要だ。
IBM Data Studioを起動してから、Junoを更新可能なサイトにする。
その状態ならば依存関係のチェックは通る。


で、そこからインストールせずに、外部ネットワーク接続できない環境のために手を動かしだしたため、実際にプラグインが入るところまでは確かめていない。また今度確かめるさ。


Websphere Developer Tools for Junoは、zipで落としてこれるのでそれを使う。ただ、Junoでのメンテが続けられるのかは心もとない、もう1年メンテされてないように見える。


さて、本命の問題はJuno自体の更新。


p2リポジトリをミラーしてくることにした。
前々からやろうと温めていた。
ミラーリングの方法は普通に載っているので理解には苦しまない。


問題は会社のプロキシ越えだ。
昨今のEclipseのネットワーク周りの具合の悪さは私の行く手をしばしば阻む。


それを回避するのにココが参考になった。

org.eclipse.ecf.provider.filetransfer.excludeContributors=org.eclipse.ecf.provider.filetransfer.httpclient
この部分が特に。
他の指定は前から知ってた、Javaでプロキシ越えたい人を知っている内容だろう。
これでクソったれなhttpclientを迂回してくれる。
これを入れないと、プレファレンスのネットワーク設定が優先されてしまう。


ミラーリングのための引数の後ろに-vmargs付けてシステムプロパティ書く感じでいける。
他にeclipseに渡して良かったのは、-consolelogくらいかな。
コンソールログでダウンロードに詰まってるファイルがわかる。


それと-ignoreErrorsを付けないと、エラーでダウンロード止まるので、付けた方がいい。さもないと、5個くらいで止まったりする。
あとなんだっけ、そうだ、-dataでワークスペースを渡してたはずだ、それをやって何もないワークスペースに.metadataフォルダ作らせてた。そこにログ残る。


さて、ダウンロード出来なかったファイルが大量にあるものの、なんちゃってミラーができたので、それを使ってみた。


残念。
依存関係のチェックは越えたけど、リポジトリにJarが足らなくて最終的にはプラグインを入れられなかった。現段階で8個くらい?必要なのが足らなかったみたいだ。
きっと、きっちりダウンロードできていれば、プラグインは入るはず。


次なる問題はなんだ。
きっとsite.xmlの形式の更新サイトたち、別のプラグインたちだ。
なんかいい方法ないかな。
rsync使えるかな。
wgetでいけるかな。
robocopyとかネットワーク越えられるの?
PowerShellはちと辛いかな。
いやいや、まずはsite.xmlの中身を評価できる方法が必要でしょ。


これかな?きっとこれだ。
おう、いえい、なんか出来そうな気がしてきたぞ。



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


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