きどたかのブログ

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

JenkinsとGradleとz/OS

z/OSをJenkinsスレーブにするのは億劫だ。
過去にJNLPでやったことはある。


今回は真っ向勝負でsshでスレーブにすることを試している。


現在一番参考になるのはコレ。


Jenkinsのマスターとスレーブが通信する際に、やはりASCII系のfile.encodingでないと上手く開かない。それは大昔にやったJNLPで気付いている。

このURLでは、USSのFile Tagを使っているが、本当にこれが有効であるのかは自信が持てないものの、Jenkinsジョブに作った「シェルの実行」が動くようなったことは確かではある。


IBM_JAVA_ENABLE_ASCII_FILETAG=ON
この環境変数は、公式には確認できていない。
_BPXK_AUTOCVT=ON
_CEE_RUNOPTS="POSIX(ON),FILETAG(AUTOCVT,AUTOTAG)"
この二つは確認できる。


_BPXK_AUTOCVT=ONは、IBM1047とISO8859-1のコンバージョンしかしないので、file tagを1208(UTF-8)で付けていても意味がねーな。
_BPXK_AUTOCVT=ALLにしやがれと。
だからといって、UTF-8の日本語が1047になるかってんだよ。
だから、FILETAGを使うとしても慎重にならざるをえない、銀の弾丸はなーい。


bin/gradleは、/bin/shでは解釈できない構文を使用しているため、書き換えが必要。とりあえずiconvで1047にして、構文を書き換えて対応している。Javaのオプションのところだ。面倒臭いから、IBM_JAVA_OPTIONS環境変数に突っ込むとかでもいい気がする。
もしくは、自分でbash on z/OSをビルドしてみるとか?  嫌だね。
z/OSで動くbashは、CPC当たりの年間サポートが2000ドルで受けられる。
サポートなしなら、タダでいけるってことか?
ちょっとよく読んでおこう。
サポート料もそこまで高くないし、生産性もいくぶん上がるかもしれないので、わりと検討の価値はかもね。


Jenkinsジョブで、Invoke Gradleを使って、EBCDICに書き換えたgradle(FILETAGはとくに変えてない)を叩きにいくと、
EDC5130I Exec format error になった。
_BPX_SPAWN_SCRIPTを使って回避。
先頭にbashが残ってるせいだったりするのかな?
まー、回避できてるから追求はおいておこう。


gradleのデーモンが動くとやばい。
たしか、sun.io.ConversionBufferFullExceptionがおきる。
正確に解析できてないんだが、新規プロセスでDaemonを立ち上げて、そこへ元のプロセスからGreetingを投げつけたあとに、アウトプットを解析するところで起きてたはず。まあ、文字コードの問題だ。
DaemonOutputConsumerが、デーモンプロセスの標準出力を読み込んでいるようだ。
デーモンプロセスの標準出力は、-Dfile.encodingでは変わらず、-Dconsole.encodingで変わる。
元プロセスがScannerでInputStreamを読み込むと、デフォルトエンコーディングで読んでしまう。
元プロセスは-Dfile.encoding、デーモンプロセスは-Dconsole.encodingということになる。
さて、元プロセスは、ISO8859-1だとかUTF-8で、デーモンプロセスは-Dfile.encoding=UTF-8で-Dconsole.encoding=IBM1047な状況でsun.io.ConversionBufferFullExceptionだったかな。
では、デーモンプロセスの-Dconsole.encodingをUTF-8に変えればどうなるか?
たしか標準出力が化けるので、化けた文字のストリームを受け取ることになり、EncodedStream.EncodedInputクラスあたりで、Unexpected value 240 received. It seems the stream was not encoded correctly.がでたような。。。どっちのどこいじったパターンだったかもう思い出せないよ。


とりあえず、デーモンプロセスの標準出力の箇所は詰んでると思う。
だから、DaemonOutputConsumerなどにパッチをあてる決断をした方がいいと思う。
デーモンプロセスの標準入力のほうはまだ探りきれてない。。。
githubからいろいろ落としてくるのが億劫だ。。。いろんなところでStream使ってるから、どこで文字コードの問題を引き起こすのか追いかけづらい。


しばらくは、デーモンが動かないようにしている。
gradle.prorertiesにデーモン用のjvmargを書かないこと、--daemonを渡さないこと。
bin/gradleに-Dfile.encodingを渡すのはOKだったかな。もしダメなら、IBM_JAVA_OPTIONSで、gradleに気付かれないように密やかに渡す。


gradleの-Dfile.encodingはASCII系でないといけない。そうしないと、依存関係の解決で、リポジトリからjarを取得するのに、ハッシュが合わなくなる。


Jenkinsジョブのコンソールログがちょこちょこ化ける問題は、まだ解析していない。


JarタスクでMANIFEST.MFがNoSuchFileExceptionで、chmod 644失敗しーの、結果としてcopyに失敗する問題にでくわした。
build/tmp/jar/META-INF/MANIFEST.MFにファイルはある。すでに644。
おい、どーした。


とりあえずJarタスクを-xでスキップして、テストを動かしたらば、jacoco-agentのMANIFEST.MFでほぼ同様の事象に出くわした。なんで解凍する必要があるんだよ。


道程は果てしなく長い模様。

ファイルの中身全体をJavaの正規表現でマッチングしたいんだが

PatternやMatcherを使う想定。


まず、Pattern#compileして、Patternを作る。
複数行にしたいならフラグも考える。


PatternができたらMatcherを作りたい。
そのとき必要なのはCharSequence。
そこはファイルの内容全部を渡したいが、
Javaヒープ使いたくないな。
FileChannelからmapして、MappedByteBufferを作って、CharsetからCharsetDecoder作って、単純なdecodeではなく、引数にCharBufferもあるdecodeを呼びたい。
単純なdecodeだと恐らく単純なCharBufferが作成されてしまい、きっとヒープに展開されるだろう。それは勘弁してもらいたい。
そのCharBufferは、ByteBuffer#allocateDirectしたByteBufferのasCharBuffer()にできないだろうか。CodeResultの扱い方は今度書きながら考える、昔書いたときはどうやってたんだろう。。。


目論見としては、ほとんど全部ヒープ外になってくれることを考えている。MappedByteBufferは、デコード後にとっとといなくなってほしい。GC起きないと厳しいだろうな。


allocateDirectするサイズがうまく見積もれない。デコーダから、averageCharsPerByteを取り、見積もるのが妥当なんだろう。
MappedByteBufferのlimitに、平均charsをかけて、charのバイト数の2をかけるのか?
そんでもって、どこかメモリ確保しやすい適当なところで繰り上げるか。
本当にlimitでええんやろか?
mapするときにチャネルのsizeを渡すつもりで、そのサイズと同じ値がlimitにくるはず。


瞬間的にヒープ外にかなり負担がかかりそう。
JVMオプションで拡げる必要がでてくるかもしれない。
GC起きないといけないし、何度も同じことやるとNative OOMコースになる可能性があるやも。それに寿命が短いバッファになる想定なんで、使い方としてはあまり納得がいくものではない。


むむぅ、小さいファイルなら非ダイレクトにしたほうが安全かもしれないしホント難しい。


ファイルの中身をCharBufferとして持てることで、正規表現の幅は広がる。
簡単な正規表現でしかないのなら、readLineして正規表現すればほとんどのことができるんだけど、複数行をやりたくなると、CharBufferを使いたくなる。


複数のPatternを用意して、初めに作成したMatcherに対して、usePattern呼び出しで、パターンの切り替えもできると思う。
DOTALLやMULTILINEをどんな感じに使うかはいろいろあるだろう。


あとは、DOTALL、否定先読み、前方参照/後方参照、最短一致あたりをコネコネ使えば、出現順不同なログの複数アサーションができるようになるんじゃねーのかな。
出現行の順序だけでなく、1行内のデータの出現順序まで順不同だった場合に、正規表現であわわあわわするんだろうけど、グループがネストした場合の参照番号の規則もちゃんと説明があるので、ゆっくりじっくり書けばなんとかなりそうだ。



Knowledge Center Mobile Betaだと!?

朗報。


製品フィルタをかけられるな、よしよし。


英語限定のやり方はどうしよう。
一応「言語の変更」が上のところから出来る。


Safariのほうが横幅合う、Chromeだと横幅が若干あわない。


困った。
一度検索しないといけない。
あらかた場所を知っているのに検索でヒットさせないといけない。


ある程度、固まった単位の読書をしたい場合、たとえばインストールまわりを読むのに、あまり適さない。


検索結果の各見出しが横に長くて途中で切れて読めない。


WASのJythonやらMBeanやらは探しにくいなぁ。そこはPC版でよさそうな単語をピックアップしてからモバイル版に戻ればいいか。

WebSphereのAntタスクが動かなくなってた

ws_antは未使用。
バージョンアップ後のテストで発覚。

症状

java.lang.NoClassDefFoundError:
javax.annotation.sql.DataSourceDefinition
アノテーションが見つからなくなったそうだ。


解決策

ここを読みなさい。


これを読んだ上で、問題となったAntタスクのネスト要素にjvmargを付け足して対応した。


開発ネットワークにp2リポジトリを立てる

開発ネットワークはインターネットにアクセスできず、プラグインのメンテナンスが大変だ。


dropinsで頑張るやり方もあるが、知らぬ間に誰かが継ぎ足した感じになったり、複数人に対したメンテナンスが悪い気がする。


現在試しているの以下のプラグインたち。
subversiveとconnector
eclemma
websphere developement tools


こいつらをluna sr2 linux 64bitにねじ込む。


content.jarとartifact.jarを持つ、
いわゆるp2形式なものは簡単だ。


難易度が高いのはfindbugs
提供形態がしょぼい。
こいつについては、旧来のUpdate Managerの形式のようだ。pluginsの部分しかzipになってない。
面倒臭い。
URL直接叩いてsite.xmlをぱくる。
site.xmlにfeatureのパスが書かれているので、
そこにあるjarを取ってくる。
featureのjarにはfeature.xmlしか入っておらず、そこにpluginのパスが書かれているので、これまたURL直接叩いて取ってくる。
必要なものが揃ったので、これで構築した。
dropinsにfeatureなしのpluginのみで認識するものもあるが、findbugsは認識されなかったみたいで、仕方なくのことです。
ひょっとしたらURL直接叩けばartifact.jarがいたのかな。。


subversiveはp2形式なので、解凍して置くだけで、とっとと更新サイトになる。
更新サイトとはいっても特定バージョンしか入ってない。
余計なsite.xmlが混ざっていたかもしれないが、放置しといた。たぶん互換性のためにあるものです。
connectorは3種類あるが、オールマイティなallplatformを使うように改めるつもりだ。


プラットフォーム限定
オールプラットフォーム
プラットフォーム非依存(svnkitの最新jar)


いまは最後の単一Jarをdropinsに放り込んでるが、手法がそこだけ違ってくるので、オールプラットフォームにでもしておく。
でも、javaHL使う予定はない。


checkstyleとeclemmaはp2形式で何も問題ない。


wdtは、Web Developement Toolsのフィーチャーが入らなかった。
いちおう前提となるluna sr2 jeeなんだが。
Linuxだからか??
gmf-rutimeが足らず
com.ibm.icu.textが足らず
emf.workbenchが足らず
どんどん芋づる式に足らないものが増えていくし、そんなバージョンどこにあるんだよってなる。
やめた、やめた。
そのフィーチャーは諦める。


p2リポジトリを作ったあとは、
それらをシエルを書いてインストールする。
まずeclipseはtar -xzfして用意。


org.eclipse.equinox.p2.directorは超むずい。


dropinsに放り込むことができるのかと思ったら、ちょっと認識が違っていた。
そこは諦めた。


installIUsするのに、先にlistさせてみるも、
なんだか数が多くてどれを選べばいいか分かりにくいこともあるので、いちどGUIを立ち上げて調べたほうがいい。


profileオプションは付けなくてもいい。
よくSDKProfileを指定している例があるが、それはRCP次第だろう。もしくは自分のやりたいことと違うのかも。
指定したいのであれば、
eclipse/cofiguration/config.iniの中に書いてある。


destinationオプションにはeclipseのフォルダを指す。


bundlepoolオプションは指定しない。
bundlepoolの指定先をdropinsのプラグイン単位フォルダにしている例があるけれど、けっこうそこがハマったところだ。
初回のプラグインのフォルダに、2回目以降のプラグインのJarたちが入っていってしまう。
2回目のプラグインのフォルダには、無味乾燥なartifact.xmlができてしまう。
これはダメパターンだ。
それなのでdropinsに置くのは諦めた。
しかも、一度dropinsを消しても、初回のbundlepoolの場所を覚えているので面倒臭い。
起動時にもチェックしているので、裏で余計なログがでている。
諦めたので、eclipse/featuresおよびeclipse/pluginsに入っていくことになる。


repositoryオプションは足らない依存関係を解決するためのすべてを書かないといけないのだが、インターネットにアクセスできない以上、自前の更新サイトしか指定していない。
そもそものluna sr2に備わっているものは、destinationの指定で解決してくれているようだ。
0.0.0のバージョンが見つからないと出たりするなら、それはきっと指定が間違ってる。


多少の妥協はあれど、やってみたかったことはおおよそ実現できそうだ、



Websphereとファイアウォール

以前、jythonで書いたスクリプトでserverindex.xmlをなめて情報を吸い出し、lokkitコマンドで設定するものを書いた。


ただ、ポート番号がアスタリスクの部分は無視して、設定しており、今回その部分で問題が起きたので、したためておく。


BOOTSTRAP_ADRESSはちゃんと設定してたんだが、ORB_LISTENER_ADRESSはアスタリスクなもんで、RMI通信するとファイアウォールにかかってしまった。




このページ、およびここからリンクで辿れる以下のページは目を通しておくといい。


アスタリスクになってると、ローカルポート範囲から使うはずだ。
カーネルパラメータのローカルポート範囲を全部開けるとかありえないので、WAS設定変えて、そこだけ開けるようにしないといけない。


まだ仕込んでないポートあったなぁ。
思いつくのはデバッグサービスのポートと、healthcenterのポートあたり。
healthcenterのほうは、リアルタイムで繋がないならポートの指定は不要だろう。自分はheadlessで動かしたことあるので困らない。


デバッグサービスのポートは面倒だ。
serverindex.xmlに書いてあるわけではなく、たしかserver.xmlをなめる必要があって、常時必要なもんでもないし、7777が初期値で、大抵の場合、全サーバで重複したポートのままになってる。
あと、書き方が二通りある。
デバッグサービスとして用意されてるページのところでやるか、JVMのページのところでjdwp関連の設定で書く二通りになる。
前者は、後者の設定を簡略にできるだけのものというイメージ。


必要になったときに考えることにする。



Jenkinsのラベル式

どう使うのが良いのだろうか。


少しだけ触った印象では、
あるジョブを実行してよいノードを条件付けるために使うものに思える。制限するっていうのだから当たり前か。


細かく条件としてのラベルを書くこともできなくはない。
シェルを動かすから、ノードにLinuxラベルを付けて、ジョブのラベル式にもLinuxを入れておく、そんな感じだろうか。


でも、やればやるほどラベルが増える。
bashじゃなくてkshじゃないと動かない?
perl入ってないと正規表現のところ動きません?
やればやるほどてんやわんや。


仮にRHEL6.5ラベルを付けたノードがあり、バージョンアップ対応でRHEL7.1をこさえた別ノードで動作確認をさせるためには、ジョブのラベル式も書き換えないといけない。
なかなか面倒くさい。


ラベルを使い、負荷分散をするのには使える。
まるっきり同一構成の環境を複数ノード作り、それぞれのノードに同じラベルを付ける。
ジョブのラベル式には、その単一のラベルを書く。でも、どちらのノードも混雑してたら、どちらのキューに積まれるのだろうか、試したことがない。この使い方がわりとしっくり来る。


ラベルは、ノードのローリングメンテナンスに使えるかもしれない。


ラベルは、アクセス制御に使えるかもしれない。テストアプリの稼働環境が非スレーブで、そのテスト環境にリクエストを投げつけてよい唯一のスレーブに、それと分かるラベルを付けて制御する形式。
ああ、でも、その唯一のスレーブで動かなくてよいジョブには、どう書けばいいんだろう。ジョブのラベル式には否定を書けるんだっけかな。
なんだかんだ嫌になって、ノード=ラベルになってしまいそうだ。


とりあえず、細かくやればやるほど、直すところが増えるので、やり過ぎないようにしよう。

ノードのラベルは空白区切り、
ジョブのラベル式は&&や||を使って書く。
記号の前後に空白を付けても、裏で作られるラベル空白が取り除かれてるようだ。
試してないけど、A&&BとB&&Aは同じ意味を持つラベル式だけど、裏で作られるラベル式はそのままの文字列で作られるんだろうな、きっと。