はじめに
自社z/OSテスト環境にてVolumeごとの使用量を確認したいことがありました。
ISPFの3.4のDat Set List Utilityにて、Volume指定してVTOC情報見れば使用率/空き状況は分かりますが、大量のVolumeがあると一つ一つそれを調べていくのは億劫です。
JCLでさくっと出せる方法を教えてもらったので試してみました。
ISPFでの確認方法
ISPFの3.4のメニュー(Data Set List Utility)にて、Volume serialにVolume名を指定し、OptionsにVを指定してEnter
すると、Volumeの使用率なんかが確認できます。(Volume Data以下の%Used)
上の例だと使用率150,255TrackのVolume(3390-9型)の65%が使用されていることが分かります。
沢山Volumeがあると、このように一つ一つVolume調べていくのは非常に効率が悪いです。
DCOLLECT / ICETOOLを使用した確認方法
DCOLLECTというAMSのユーティリティーが提供されており、これでVolumeの情報を取得することができます。
参考: z/OS DFSMS - Abstract for DFSMS Access Method Services Commands - DCOLLECT
ただし、このユーティリティーを使って取得される情報はそのままだと人が見て分かる形になっていません。DCOLLECTで取得されるデータのフォーマットは以下の通りです。
参考: DCOLLECT Output Record Structure
従ってこれをフォーマットしてあげる必要がありますが、フォーマットにはDFSORTに含まれるICETOOLというユーティリティーが利用できます。
参考: z/OS DFSORT - z/OS DFSORT Application Programming Guilde - Using ICETOOL - OVerview
JCL実行
実際に DCOLLECT および ICETOOL を使用したJCLを作成してVOLUMEの使用量を出力するJCLを作って流してみます。
※DCOLLECTツールを使う際に、FACILITYクラスのSTGADMIN.IDC.DCOLLECTプロファイルに実行ユーザーのREAD権限が必要でした。
参考: Command and keyword related profiles
Sample JCL
//DCOLLECT JOB MSGLEVEL=(1,1),MSGCLASS=X,CLASS=A
//STEP1 EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//OUTDS DD DSN=&&TEMP,DISP=(NEW,PASS),
// LRECL=644,RECFM=VB,BLKSIZE=648,
// SPACE=(TRK,(10,10),RLSE),UNIT=SYSDA
//SYSIN DD *
DCOLLECT OFILE(OUTDS) -
VOLUMES(CICVS*, -
CIDB*, -
CIDVM*, -
CTG*, -
CTS*, -
CWDB*, -
IDZ*, -
IODM*, -
OM53*, -
PDT*, -
RDZ*, -
WODM*, -
ZCON*, -
ZSPK*) -
NODATAINFO
/*
//STEP2 EXEC PGM=ICETOOL,REGION=0M
//SYSOUT DD SYSOUT=*
//TOOLMSG DD SYSOUT=*
//DFSMSG DD SYSOUT=*
//REP01 DD SYSOUT=*
//INDD DD DSN=&&TEMP,DISP=(OLD,DELETE)
//OUTDD DD SYSOUT=*
//*UTDD DD DSN=CICSSHR.CICS004.DCOLLECT.TEST2,DISP=(NEW,CATLG),
// UNIT=SYSDA,VOL=SER=Z9CI01,SPACE=(TRK,(10,10),RLSE),
// LRECL=120,RECFM=FBA,BLKSIZE=0
//TOOLIN DD *
DISPLAY FROM(INDD) LIST(OUTDD) BLANK -
TITLE('DASD SPACE INFORMATION') -
LINES(999) -
HEADER('VOLSER') ON(29,6,CH) -
HEADER('% FREE') ON(40,1,BI,A1) -
HEADER('ALLOC(MB)') ON(45,4,BI,/KB,A1) -
HEADER('FREE(MB)') ON(41,4,BI,/KB,A1) -
HEADER('VOL(MB)') ON(49,4,BI,/KB,A1) -
HEADER('STORAGE GROUP') ON(87,8,CH) -
AVERAGE('AVERAGE') -
TOTAL('TOTAL')
/*
//
実行結果(OUTDD)
1DASD SPACE INFORMATION
VOLSER % FREE ALLOC(MB) FREE(MB) VOL(MB) STORAGE GROUP
------ -------------------- -------------------- -------------------- -------------------- -------------
CTS53B 8 7,505 614 8,119 SGCTS53
CTS53C 0 8,093 25 8,119 SGCTS53
ZCON02 60 3,226 4,892 8,119
IODM01 0 8,111 7 8,119
IODM02 32 5,539 2,579 8,119
IODM03 19 6,576 1,543 8,119
CTG91A 70 2,426 5,693 8,119
CTS53A 20 6,477 1,641 8,119 SGCTS53
IODM04 16 6,856 1,262 8,119
IODM05 30 5,660 2,459 8,119
ZSPK01 1 8,010 109 8,119
WODM01 100 29 8,089 8,119
PDT001 78 1,817 6,302 8,119
WODM02 84 1,260 6,859 8,119
CTS54A 35 5,290 2,828 8,119
CTS54B 29 5,732 2,387 8,119
IODM0A 8 7,440 678 8,119
ZCON03 11 7,206 913 8,119
ZCON04 22 6,309 1,810 8,119
CTS52A 5 7,679 440 8,119 SGCTS52
CTS52B 10 7,333 785 8,119 SGCTS52
CTS52C 98 149 7,969 8,119 SGCTS52
IDZ003 27 5,912 2,206 8,119
IODM06 94 506 7,613 8,119
IODM07 34 5,389 2,729 8,119
OM53CA 38 5,021 3,098 8,119
OM53CB 22 6,293 1,825 8,119
IDZ001 9 7,414 705 8,119
IDZ002 13 7,030 1,089 8,119
CWDB01 88 970 7,149 8,119
CWDB02 26 5,985 2,134 8,119 SGCWDB
CWDB03 93 581 7,538 8,119 SGCWDB
WODM05 0 8,116 3 8,119
CIDVM1 45 4,459 3,659 8,119
WODM08 0 8,110 9 8,119
WODM09 0 8,110 9 8,119
WODM06 2 7,928 190 8,119
WODM07 1 8,021 98 8,119
IODM08 43 4,659 3,460 8,119
IODM09 29 5,735 2,383 8,119
IODM10 7 7,513 606 8,119
WODM10 25 6,082 2,037 8,119
WODM11 0 8,112 7 8,119
WODM12 50 4,060 4,059 8,119
CTG92A 65 2,847 5,272 8,119
ZCON01 25 6,121 1,998 8,119
CTS32A 2 2,642 63 2,706 SGCICSPP
CTS32U 46 1,453 1,253 2,706
CTS32B 4 2,608 98 2,706 SGCICSPP
CTS32C 3 2,632 74 2,706 SGCICSPP
CTS32X 66 911 1,795 2,706
RDZ002 100 2 2,703 2,706 SGRDZ
IODM0B 18 6,669 1,450 8,119
IODM0C 23 6,267 1,852 8,119
CTS62A 62 3,101 5,017 8,119
CTS62B 38 5,061 3,058 8,119
RDZ001 100 2 2,703 2,706 SGRDZ
CIDB01 28 1,935 770 2,706
CIDB02 2 2,656 50 2,706 SGCIDB2
CIDB03 1 2,690 15 2,706 SGCIDB2
CTS51A 15 6,938 1,181 8,119 SGCTS51
CTSTLA 19 6,545 1,574 8,119 SGCTSTL
CTS51B 7 7,554 565 8,119 SGCTS51
AVERAGE 31 4,974 2,285 7,259
TOTAL 2,006 313,363 143,981 457,367
Volumeごとの使用量がきれいに取得できました。すばらしい!
JCL解説
上のSample JCLを読み解いてみたので解説します。
STEP1: DCOLLECT
参考: DCOLLECT - Optional Parameters
DCOLLECTのオプションVOLUMESにて調査したいVOLUMEを複数指定することができます。ここではワイルドカードとして「*」(アスタリスク)指定も可能です。
今回はVolumeの情報だけ必要なので、NODATAINFOを指定することでデータセット関連情報の出力を抑止しています。
STEP2: ICETOOL
参考: ICETool - DISPLAY operator
DCOLLECTで取得した情報をICETOOLのDISPLAY operatorを使ってフォーマットしています。
各項目の値の取得
肝になるのは実行結果の各列部分の取得だと思いますが、これは「HEADER(xxx) ON(yyy)
」という箇所で表しています。
例1: HEADER('VOLSER') ON(29,6,CH)
これはVOLSER名を取得している部分で、出力時のHEADERの名前として'VOLSER'という文字列を指定しています。そこに表示させる値をON(29,6,CH)
で指定しています。
ONに指定するパラメーターは、元データの位置、長さ、型を表します。つまり、上の指定は「元データの29番目の位置の6バイト部分をキャラクター型のデータとして'VOLSER'の項目として表示させる」ということになります。
ここで第1引数の"位置"(p)を示す数値がちょっと分かりにくいので補足です。マニュアルには以下の記述があります。
ON(p,m,f)
Specifies the position, length, and format of a numeric or character field to be used for this operation.
...
p specifies the first byte of the field relative to the beginning of the input record. p is 1 for the first data byte of a fixed-length record and 5 for the first data byte of a variable-length record as illustrated in the following (RRRR represents the 4-byte record descriptor word):
元データがvariable-lengthのレコードの場合、先頭4バイトのrecord descriptor wordを除いた5バイト目(offset:4)が実データの先頭データを指すので、先頭データを指定したい場合はONパラメータの第一引数としては「5」を指定することになるようです。
さて、DCOLLECTで取得されたデータのレコードフォーマットは以下に記載があります。
参考: DCOLLECT Output Record Structure
この表のうちVolume関連の情報はRECORD TYPEが"V"の場合のフォーマットということなので、以下の辺りに記載があります。
この表からoffset:24 の6バイト分がVolume名を示すということになりますが、ここでのoffsetは0バイトからカウントされているのと、variable-lengthの先頭4バイト分を考慮し、ICETOOL DISPLAYのONで指定する位置として「29」を指定するということになります。つまり、上の表のoffset値+5をONの位置情報として指定すると、取得したいフィールドがポイントできるということになるようです。
第2引数はLength(byte)なのでそのまま。
第3引数は型を表します。今回は文字列(Character)なのでCharacterを示すCHを指定しています。他にもBI(Binary), PD(Signed Packed Decimal)など多様な型が指定できるようです。このツールはSMFデータのフォーマットにも対応しているようで、TOD形式などにも対応しているようです。
例2: HEADER('% FREE') ON(40,1,BI,A1)
これはVolumeの空き容量のフィールドの定義をしている部分です。先の例にならってONのパラメーターを判別して指定します。
DCOLLECTのStructureで言うと、「VOLUME INFORMATION (RECORD TYPE "V")」の中の以下の部分に相当します。
offset:35なので35+5=40
を位置情報として指定し、Lengthは1、型はBinaryとします。
ここではONのパラメーターとして追加で第4引数が指定されています。第4引数以降は表示形式のフォーマットを指定する部分で、複数の引数を指定できます。
ON(p,m,f,formatting)
Specifies the position, length, and format of a numeric or character field to be used for this operation and how the data for this field is to be formatted for printing. The BLANK operand is automatically in effect.
See ON(p,m,f) for further details.
例3: HEADER('ALLOC(MB)') ON(45,4,BI,/KB,A1)
これはVolumeの使用されている容量についてのフィールドの定義をしている部分です。先の例にならってONのパラメーターを判別して指定します。
offset:40なので40+5=45
を位置情報として指定し、Lengthは4、型はBinaryとします。
この例では、ONのformattingに関する引数"/KB"が追加で指定されています。
/x
specifies division of the numeric data for this field before formatting. x indicates the division factor to be used as described later in this section. The resulting values are rounded down to the nearest integer. Statistics (TOTAL, MAXIMUM, MINIMUM, AVERAGE, BTOTAL, BMAXIMUM, BMINIMUM, BAVERAGE) and column widths reflect the divided numbers.
...
/KB
specifies division by 1024 before formatting. For example, 1234567890 is shown as 1 205 632 with ON(45,10,ZD,/KB,A3).
/KBを指定することで1024で割り算した結果を表示してくれます。元のデータがKB単位のデータですので、それを1024で割ることで、MB単位のデータに換算して表示してくれるということになります。そのためHEADERの文字列としては"ALLOC(MB)"という指定にしています。
その他
オプション: LINES(999)
デフォルトだと58行単位でページが分かれて、途中に余計なヘッダー情報が出力されてしまってうざいです。ページの区切りを無しするオプションが見当たらないので、1ページに含められる行数を最大の999に指定しています。
オプション: AVERAGE('AVERAGE')
数値フィールドについて、平均値を最後に出力してくれます。
オプション: TOTAL('TOTAL')
数値フィールドについて、合計値を最後に出力してくれます。
おわりに
こういう情報をコマンド一発で簡単に取得できない、というのがz/OSの使い勝手が悪い所なんだよなぁとつくづく思います。
ググっても微妙に情報が古かったり、ピンポイントで必要な情報が自分では見つけられませんでした。詳しい人に聞いたらサクッとサンプル作ってくれました。こういうのすぐ作れる人すごいですねぇ。分かる人にとっては簡単なことなのかもしれませんが...。
「DCOLLECTとICETOOLでなんとかなる」ということが分かった後では、以下の記事をググって見つけることはできました。
参考: z/OS環境でディスク容量を効率利用できる「シンプロビジョニング機能」とは ~その利点・効果と利用時の考慮点
この記事の中に、まさに欲しかったサンプルがそのまま載ってました。
本当はJCLではなくもっと汎用的なUSSコマンドとかREST APIで取得できればよいと思って探したのですが見つけられませんでした。レコード形式で出してそれをさらに自分でフォーマットするってイマドキじゃないですよねぇ。最初からCSVとかJSON形式で出してくれればいいのに。不親切だよなぁ。
z/OSMFのREST serviceに以下のAPIがあったのでいけるかと思ったのですが、
Get a volume definition
これはSMSとして提供しているサービスのようなので、どうやらSMS管理のVolumeの情報しか取得できないようでした。惜しい!
AIとかやる前にこういう所をなんとかして欲しいと思うのですが...