z/OSのVolumeごとの使用量を確認する方法

# はじめに
自社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
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/37bd118b-5c57-e019-a95c-9fb678655c04.png)

すると、Volumeの使用率なんかが確認できます。(Volume Data以下の%Used)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/4792eba2-3409-70b9-1914-1c8870034eb7.png)
上の例だと使用率150,255TrackのVolume(3390-9型)の65%が使用されていることが分かります。

沢山Volumeがあると、このように一つ一つVolume調べていくのは非常に効率が悪いです。

# DCOLLECT / ICETOOLを使用した確認方法

DCOLLECTというAMSのユーティリティーが提供されており、これでVolumeの情報を取得することができます。
参考: [z/OS DFSMS - Abstract for DFSMS Access Method Services Commands - DCOLLECT](https://www.ibm.com/docs/en/zos/2.5.0?topic=commands-dcollect)

ただし、このユーティリティーを使って取得される情報はそのままだと人が見て分かる形になっていません。DCOLLECTで取得されるデータのフォーマットは以下の通りです。
参考: [DCOLLECT Output Record Structure](https://www.ibm.com/docs/en/zos/2.5.0?topic=output-dcollect-record-structure)

従ってこれをフォーマットしてあげる必要がありますが、フォーマットにはDFSORTに含まれるICETOOLというユーティリティーが利用できます。
参考: [z/OS DFSORT - z/OS DFSORT Application Programming Guilde - Using ICETOOL - OVerview](https://www.ibm.com/docs/en/zos/2.5.0?topic=icetool-overview)

## JCL実行

実際に DCOLLECT および ICETOOL を使用したJCLを作成してVOLUMEの使用量を出力するJCLを作って流してみます。

※DCOLLECTツールを使う際に、FACILITYクラスのSTGADMIN.IDC.DCOLLECTプロファイルに実行ユーザーのREAD権限が必要でした。
参考: [Command and keyword related profiles](https://www.ibm.com/docs/en/zos/2.5.0?topic=class-command-keyword-related-profiles)

Sample JCL

```jcl: DCOLLECT.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')
/*
//
```

<details><summary><font color="blue">実行結果(OUTDD)</font></summary><div>


```
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
```
</div></details>

Volumeごとの使用量がきれいに取得できました。すばらしい！


## JCL解説
上のSample JCLを読み解いてみたので解説します。

### STEP1: DCOLLECT
参考: [DCOLLECT - Optional Parameters](https://www.ibm.com/docs/en/zos/2.5.0?topic=dp-optional-parameters)

DCOLLECTのオプションVOLUMESにて調査したいVOLUMEを複数指定することができます。ここではワイルドカードとして「*」(アスタリスク)指定も可能です。

今回はVolumeの情報だけ必要なので、NODATAINFOを指定することでデータセット関連情報の出力を抑止しています。

### STEP2: ICETOOL

参考: [ICETool - DISPLAY operator](https://www.ibm.com/docs/en/zos/2.5.0?topic=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)を示す数値がちょっと分かりにくいので補足です。マニュアルには以下の記述があります。

参考:[Operand descriptions](https://www.ibm.com/docs/en/zos/2.5.0?topic=do-operand-descriptions-2)
>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 <font color="red">5 for the first data byte of a variable-length record</font> 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](https://www.ibm.com/docs/en/zos/2.5.0?topic=output-dcollect-record-structure)

この表のうちVolume関連の情報はRECORD TYPEが"V"の場合のフォーマットということなので、以下の辺りに記載があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/d9ff1f73-df11-b8e0-08c9-abbcca438f2c.png)
この表から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形式などにも対応しているようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/3cc9aea7-0257-1138-8bca-ebe8a9938ae8.png)


---

例2: ```HEADER('% FREE') ON(40,1,BI,A1)```

これはVolumeの空き容量のフィールドの定義をしている部分です。先の例にならってONのパラメーターを判別して指定します。
DCOLLECTのStructureで言うと、「VOLUME INFORMATION (RECORD TYPE "V")」の中の以下の部分に相当します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/21d1a96b-fa8e-9c73-cb2c-513d931820cc.png)
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.
>
>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/8ca50884-826b-973e-1600-c0b763b86e8d.png)

A1というのは数値の表示形式の1つです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/774018b3-ebd2-5793-88f5-5a860ae7d119.png)

---

例3: ```HEADER('ALLOC(MB)') ON(45,4,BI,/KB,A1)```

これはVolumeの使用されている容量についてのフィールドの定義をしている部分です。先の例にならってONのパラメーターを判別して指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/4a55967e-7f66-f044-0578-60578b0217bf.png)
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環境でディスク容量を効率利用できる「シンプロビジョニング機能」とは　～その利点・効果と利用時の考慮点](https://www.imagazine.co.jp/mainframe-thinpro/)
この記事の中に、まさに欲しかったサンプルがそのまま載ってました。

本当はJCLではなくもっと汎用的なUSSコマンドとかREST APIで取得できればよいと思って探したのですが見つけられませんでした。レコード形式で出してそれをさらに自分でフォーマットするってイマドキじゃないですよねぇ。最初からCSVとかJSON形式で出してくれればいいのに。不親切だよなぁ。
z/OSMFのREST serviceに以下のAPIがあったのでいけるかと思ったのですが、
[Get a volume definition](https://www.ibm.com/docs/en/zos/2.5.0?topic=services-get-volume-definition)
これはSMSとして提供しているサービスのようなので、どうやらSMS管理のVolumeの情報しか取得できないようでした。惜しい！
AIとかやる前にこういう所をなんとかして欲しいと思うのですが...