SDSFって何?
z/OSというメインフレームOSを一度でもお使いになったことのある方であれば、独特の”パネル式”インターフェースに戸惑われたことでしょう。その中でも、ジョブを管理するためのユーティリティーがSDSF (System Display and Search Facility)であり、ジョブの状態やリソースの使用状況等をリアルタイムに確認することが可能です。
このSDSF、通常は画面(パネル)で操作するものと思いますが、プログラムから操作することも可能です。しかもJavaから。
何故JavaからSDSF?
もともとは、z/OS上のJOBの終了コードを外部メッセージングツール(具体的にはSlack)に送付したい、というのがあり、SDSFにアクセスする方法をしらべたのがきっかけです。REXXでアクセスできるのは知っていたので、REXXで終了コードを取得した後何らかの方法でSlackに送信しようかと思っていたのですが、z/OS V1.12 からJavaでもSDSFにアクセスできるとのことで、じゃあ情報の取得も送信もJavaでできそうだ、ということで調べ始めました。自分自身REXXはあんまり知らないというのもあるし。
ただ、JavaのSDSFアクセスに関する記事はネットを検索してもほとんどありませんでした。まあ当然といえば当然ですが。そういうわけで、せっかくなので記事にしてやろうというのがこの記事になります。
マニュアル、Javadoc、付属のサンプルコードと、わりと充実しているので、ネットに情報がなくてもコードを書くのはそんなに困りませんでした。
動かすための設定
大前提として、z/OS上でしか動きません。USS上でもJavaバッチででも動くのですが、とりあえずUSSで動かしてみましょう。CLASSPATHとLIBPATHに以下の設定が必要です。
export CLASSPATH=/usr/include/java_classes/isfjcall.jar:$CLASSPATH
export LIBPATH=/usr/lib/java_runtime64:$LIBPATH
なお、環境に問題がなければ、以下のコマンドで環境情報が出力されます。
java -cp classpath -jar /usr/include/java_classes/isfjcall.jar
ドキュメントとサンプル
-
最初はやはりz/OSのマニュアルを参照しましょう。z/OS V2.5では以下のURLに記載されています。お使いのz/OSバージョンに合わせて該当のページを見てください。
Using SDSF with the Java Programming Language
https://www.ibm.com/docs/en/zos/2.5.0?topic=guide-using-sdsf-java-programming-language -
z/OS USS上の /usr/lpp/sdsf/java/classes/isfjcallDoc.jar というファイルに、JavaDocが含まれていますので、ダウンロードしてPCで見てみましょう。
-
z/OS USS上の /usr/lpp/sdsf/java/samples に、サンプルのJavaプログラムがあります。(上記isjfcallDoc.jarにも含まれています)。以下のサンプルがあります。
- ISFBrowseJobDataSetSample.java
- ISFStatusオブジェクトからJobデータ・セットをブラウズするサンプル
- ISFBrowseSample.java
- Spoolデータ・セットをブラウズするサンプル
- ISFBrowseStatusJobSample.java
- ISFStatusオブジェクトからSpoolデータ・セットをブラウズするサンプル
- ISFChangeJobPrioritySample.java
- Jobプライオリティーを変更するサンプル
- ISFGetJobStepsSample.java
- 一つのJobのJobステップ情報をリストするサンプル
- ISFGetJobsSample.java
- Queue上のJobをリストするサンプル
- ISFHealthCheckSample.java
- Health Checkをブラウズするサンプル
- ISFLineResultsSample.java
- 追加情報を含むOperlogレコードを示すサンプル
- ISFSearchOperlogSample.java
- Operlogをブラウズするサンプル
- ISFSearchSyslogSample.java
- Spoolデータ・セットをブラウズするサンプル
- ISFSearchSyslogSample2.java
- Spoolデータ・セットをブラウズするサンプル
- ISFSlashCommandSample.java
- MVSシステム・コマンドを発行するサンプル
- ISFWhoCommandSample.java
- SDSF WHOコマンドを呼び出すサンプル
動かしてみよう
たとえば、SDSFのDA(Active User)で、ZC*で始まるJOBを見てみるとします。こんな感じ。
SDSF DA ETP1 ETP1 PAG 0 CPU/L 1/ 1 LINE 1-3 (3)
NP JOBNAME StepName ProcStep JobID Owner C Pos DP Real Paging SIO
ZC30ANGL ZC30ANGL STEP1 STC02826 LIBSRV NS FE 410 0.00 0.00
ZC30CI01 ZC30CI01 ZCON STC03150 LIBSRV IN F4 156T 0.00 0.00
ZC30MQ03 ZC30MQ03 ZCON STC03008 LIBSRV IN F4 59T 0.00 0.00
以下のプログラムを使うと、ZC* で始まるJOBNAMEとJOBIDのリストを取得できます。
import java.io.* ;
import java.util.* ;
import com.ibm.zos.sdsf.core.* ;
public class TestDA {
public static void main(String[] args) throws Exception {
ISFRequestSettings settings = new ISFRequestSettings();
settings.addISFPrefix("**");
settings.addISFOwner("*");
settings.addISFFilter("jname eq ZC*") ;
ISFActiveRunner runner = new ISFActiveRunner(settings);
List<ISFActive> objs = runner.exec() ;
System.out.println("objs.size = " + objs.size()) ;
if (objs != null) {
for (ISFActive statObj : objs) {
System.out.println(statObj.getJName() + " " + statObj.getJobID()) ;
}
}
}
}
これを実行すると、以下のような結果が得られます。
$ java TestDA
objs.size = 3
ZC30ANGL STC02826
ZC30CI01 STC03150
ZC30MQ03 STC03008
期待通り、JOBNAMEとJOBIDが得られました。
ちなみに、これはActive Users(DA)の例ですが、
- ISFActiveRunner -> ISFStatusRunner
- ISFActive -> ISFStatus
と置き換えると、Status of jobs(ST)の結果と同じになります。簡単ですね!
大まかな流れ
このサンプルプログラムのおおまかな流れは、
- フィルター設定をする(ISFRequestSettings)
ここではjname eq ZC*
というフィルターを設定しています。JOBIDで特定したければjobid eq STC02826
みたいな指定も可能です。ne(not equal)やlt(less than)のような演算子も使えるようです。 - 上記の設定をもとにrunnerを作る(ISFStatusRunner/ISFActiveRunner)
このrunnerオブジェクトを使ってSDSF操作を実行して結果を保持します。 - runnerを実行し、ステータスオブジェクトを取得する(ISFStatus/ISFActive)
複数の結果が返るかもしれません。
つぎに、JOBの中身を覗いてみよう
まずは、実際にSDSFで見てみます。さきほどのZC30ANGLの先頭でS(選択)を実行すると、こんな画面になります。
********************************* TOP OF DATA **********************************
J E S 2 J O B L O G -- S Y S T E M E T P 1 -- N
10.12.12 STC02826 ---- FRIDAY, 24 NOV 2023 ----
10.12.12 STC02826 IEF695I START ZC30ANGL WITH JOBNAME ZC30ANGL IS ASSIGNED TO U
10.12.12 STC02826 $HASP373 ZC30ANGL STARTED
10.12.12 STC02826 CWWKB0079I THE ANGEL BUILD LEVEL IS 23.0.0.9 cl230920230904-1
888 2023.9.0.0 cl230920230904-1158
10.12.12 STC02826 CWWKB0084I ANGEL HAS SUCCESSFULLY REGISTERED AS ELEMENT NAME
889 WITH THE AUTOMATIC RESTART MANAGER (ARM).
10.12.12 STC02826 CWWKB0069I INITIALIZATION IS COMPLETE FOR THE ZC30ANGL ANGEL
1 //ZC30ANGL JOB MSGLEVEL=1
2 //STARTING EXEC ZC30ANGL
3 XXBBGZANGL PROC
ちなみに画面をコピペしただけなので右端は切れています。
import java.io.* ;
import java.util.* ;
import com.ibm.zos.sdsf.core.* ;
public class TestMSG {
public static void main(String[] args) throws Exception {
ISFRequestSettings settings = new ISFRequestSettings();
settings.addISFPrefix("**");
settings.addISFOwner("*");
settings.addISFFilter("jname eq ZC30ANGL") ;
ISFActiveRunner runner = new ISFActiveRunner(settings);
List<ISFActive> objs = runner.exec() ;
ISFRequestResults reqres = runner.getRequestResults() ;
System.out.println("objs.size = " + objs.size()) ;
if (objs != null) {
ISFActive statObj = objs.get(0) ;
List<ISFJobDataSet> list1 = statObj.getJobDataSets() ;
for (ISFJobDataSet ds : list1) {
ds.browse() ;
List<String> response = reqres.getResponseList() ;
System.out.println(">>>>> DDNAME = " + ds.getDDName()) ;
for(String str : response) {
System.out.println(str) ;
}
}
}
}
}
これを実行すると、つぎのような結果になります。
$ java TestMSG
objs.size = 1
>>>>> DDNAME = JESMSGLG
1 J E S 2 J O B L O G -- S Y S T E M E T P 1 -- N O D E N 1
0
10.12.12 STC02826 ---- FRIDAY, 24 NOV 2023 ----
10.12.12 STC02826 IEF695I START ZC30ANGL WITH JOBNAME ZC30ANGL IS ASSIGNED TO USER LIBSRV , GROUP SYS1
10.12.12 STC02826 $HASP373 ZC30ANGL STARTED
10.12.12 STC02826 CWWKB0079I THE ANGEL BUILD LEVEL IS 23.0.0.9 cl230920230904-1158 / 888
888 2023.9.0.0 cl230920230904-1158
10.12.12 STC02826 CWWKB0084I ANGEL HAS SUCCESSFULLY REGISTERED AS ELEMENT NAME ZC30ANGL 889
889 WITH THE AUTOMATIC RESTART MANAGER (ARM).
10.12.12 STC02826 CWWKB0069I INITIALIZATION IS COMPLETE FOR THE ZC30ANGL ANGEL PROCESS.
>>>>> DDNAME = JESJCL
1 //ZC30ANGL JOB MSGLEVEL=1 STC02826
2 //STARTING EXEC ZC30ANGL
3 XXBBGZANGL PROC
:
どうでしょう、うまくとれていますね。
実際には、各DD名毎に文字列を取得しているのがわかるでしょうか。
これで、JOBIDがわかればJOBLOGを自由に読めるようになりました。
当初の目標だった、バッチの終了コードをSlackに送るということに関しては、そのJOBの最後にJavaのステップをくっつけて、「自分自身のJOBIDを取得して、そのJESMSGLGからReturn Codeに関係する部分のみ抜き出して送付」ということで実現しました。
リンク
Usinf SDSF with the Java Programming Language
https://www.ibm.com/docs/en/zos/2.5.0?topic=guide-using-sdsf-java-programming-language
zOS_Joblog_to_Slack
https://github.com/Tomo-92/zOS_Joblog_to_Slack/blob/master/README.ja.md