Windows/Linux/UnixからSSH経由でz/OSを操作する


#はじめに
[USSからREXX, シェル・スクリプトでz/OSを操作する](http://qiita.com/tomotagwork/items/10b3a83b3db65b9aea19)の応用編です。
上の記事で紹介したREXX/シェル・スクリプトを分散系プラットフォーム(Windows/Linux/Unix等)からssh経由で呼び出すことで、ダイレクトにz/OSを操作しているように見せることができます。
ここではWindows環境からの操作例を中心に記載しますが、他のプラットフォームでも基本は同様なので流用できると思います。

[マルチ・プラットフォームを扱うインフラ屋さんのための連携技術: SSH編](http://qiita.com/tomotagwork/items/b35aa09c1aa1acb3d554)で紹介している「sshコマンドでの操作」ができるようにしておくことと、「公開鍵認証」の設定をしておくことが前提です。

#事前準備
まずは、上の記事に従って、以下の2つの設定を行ってください。

* sshクライアントコマンドを実行できるようにしておく (WindowsにMinGW, MSYSを導入してpathの設定を行う)
* z/OSのSSHサーバーとWindows間で公開鍵認証の設定をしておく

それからUSS上で、公開鍵認証で使用するz/OS側ユーザーのプロファイル(~/.profile)に、環境変数として上で紹介したREXX, Shellスクリプトのパスを通しておきましょう。

```xxx:.profile例
export PATH=$PATH:/u/cics004/Shell:/u/cics004/REXX
```

#WindowsからSSH経由でSDSFコマンドを実行する

以下のようなバッチファイルをWindows上で作成します。これはUSS上に用意したsdsf.rexをSSH経由で呼び出しています。

```bat:sdsf.bat
@echo off
setlocal enabledelayedexpansion

if "%sdsf_host%" == "" (
	set sdsf_host="ePlex"
) 

if "%sdsf_user%" == "" (
	set sdsf_user="CICS004"
)

ssh %sdsf_user%@%sdsf_host% . ./.profile;sdsf.rex "%1"
```

ここでsdsf_hosts, sdsf_userはそれぞれ接続先のホスト名(or IPアドレス)、z/OS側のユーザー(公開鍵認証の設定をしてるもの)です。
このバッチでのポイントは、sshコマンドで、.profileをカレントのシェルに読み込ませてからsdsf.rexを実行している点です。実はsshコマンドでコマンドやrexxを実行する場合、.profileは自動で読み込んでくれません。そのため明示的に実行している訳です。

さて、上のバッチファイルを作ったら、Windowsの環境変数の設定で、path環境変数にこのバッチファイルのパスを通してあげれば準備完了です。

Windowsのコマンドプロンプトを開いておもむろにSDSFコマンドを投入してみましょう。(コマンドにブランクを含む場合はダブルクォーテーションでくくります)

```xxx:実行例
c:\>sdsf "D T"
RC:  0
ISFMSG:   COMMAND ISSUED
ISFMSG2.1 : ISF776I Processing started for action 1 of 1.
ISFMSG2.2 : ISF769I System command issued, command text: D T.
ISFMSG2.3 : ISF766I Request completed, status: COMMAND ISSUED.
ZOS1      2016264  19:08:26.83             ISF031I CONSOLE CICS004 ACTIVATED
ZOS1      2016264  19:08:26.83            -D T
ZOS1      2016264  19:08:26.83  STC04889   IEE136I LOCAL: TIME=19.08.26 DATE=2016.264  UTC: TIME=10.08.26 DATE=2016.264

c:\>sdsf "D M=STOR"
RC:  0
ISFMSG:   COMMAND ISSUED
ISFMSG2.1 : ISF776I Processing started for action 1 of 1.
ISFMSG2.2 : ISF769I System command issued, command text: D M=STOR.
ISFMSG2.3 : ISF766I Request completed, status: COMMAND ISSUED.
ZOS1      2016264  19:08:39.92             ISF031I CONSOLE CICS004 ACTIVATED
ZOS1      2016264  19:08:39.92            -D M=STOR
ZOS1      2016264  19:08:40.09             IEE174I 19.08.39 DISPLAY M 597
                                           REAL STORAGE STATUS
                                           ONLINE-NOT RECONFIGURABLE
                                               0M-8192M
                                           ONLINE-RECONFIGURABLE
                                               NONE
                                           PENDING OFFLINE
                                               NONE
                                           STORAGE INCREMENT SIZE IS 1M

c:\>sdsf "D OMVS"
RC:  0
ISFMSG:   COMMAND ISSUED
ISFMSG2.1 : ISF776I Processing started for action 1 of 1.
ISFMSG2.2 : ISF769I System command issued, command text: D OMVS.
ISFMSG2.3 : ISF766I Request completed, status: COMMAND ISSUED.
ZOS1      2016264  19:08:47.03             ISF031I CONSOLE CICS004 ACTIVATED
ZOS1      2016264  19:08:47.03            -D OMVS
ZOS1      2016264  19:08:47.04             BPXO042I 19.08.47 DISPLAY OMVS 601
                                           OMVS     0010 ACTIVE             OMVS=(01,FS)
```

WindowsのコマンドプロンプトからSDSFコマンドが投入できたように見えますね！素敵です。
先に示したバッチでは、接続先やユーザーは環境変数で切り替えられるようにしています。接続先が複数ある場合は、それぞれにSSH公開鍵認証の設定をしておき、環境変数sdsf_host, sdsf_userであて先ホスト名(or IPAddress),ユーザー名を切り替えればOKです！ (バッチによるコマンド実行前に、```set sdsf_host=hostname``` というように指定する)

#WindowsからSSH経由でJOBLOGを取得する

同じ要領でJOBLOGを取得するバッチを作ってみました。

##JOBID指定でJOBLOG取得

以下のようなバッチファイルをWindows上で作成します。

```bat:getJobDDs_JobID.bat
@echo off
setlocal enabledelayedexpansion

if "%sdsf_host%" == "" (
	set sdsf_host="ePlex"
) 

if "%sdsf_user%" == "" (
	set sdsf_user="CICS004"
)

set tempJobDDsListFile=tempJobDDsList.txt

ssh %sdsf_user%@%sdsf_host% . ./.profile; jobdd.rex "%1" > %tempJobDDsListFile%

FOR /F "tokens=1,2,3*" %%a IN (%tempJobDDsListFile%) do (
	scp %sdsf_user%@%sdsf_host%:%%c ./
	ssh %sdsf_user%@%sdsf_host% . ./.profile; rm %%c
)

REM del %tempJobDDsListFile%
```

このバッチでは以下のようなことをしています。
(1) jobdd.rexにてJOBID指定でDD毎のファイルをUSSのホームディレクトリに作成(作成したファイルのリストはWindows上のtempJobDDsList.txtに出力)
(2) scpでUSSからWindowsのカレント・ディレクトリにファイルをコピー
(3) USSのホームディレクトリからファイルを削除


```xxx:実行例
c:\y\temp\zos>getJobDDs_JobID JOB04888
JOB04888_JESMSGLG.txt                                                  100% 1346     1.3KB/s   00:00
JOB04888_JESJCL.txt                                                    100%  625     0.6KB/s   00:00
JOB04888_JESYSMSG.txt                                                  100%  896     0.9KB/s   00:00
JOB04888_SYSPRINT.txt                                                  100%   60KB  59.9KB/s   00:00

c:\y\temp\zos>dir
 ドライブ C のボリューム ラベルがありません。
 ボリューム シリアル番号は 2A67-11E4 です

 c:\y\temp\zos のディレクトリ

2016/09/26  11:42    <DIR>          .
2016/09/26  11:42    <DIR>          ..
2016/09/26  20:28               625 JOB04888_JESJCL.txt
2016/09/26  20:28             1,346 JOB04888_JESMSGLG.txt
2016/09/26  20:28               896 JOB04888_JESYSMSG.txt
2016/09/26  20:28            61,323 JOB04888_SYSPRINT.txt
2016/09/26  20:28               142 tempJobDDsList.txt
               5 個のファイル              64,332 バイト
               2 個のディレクトリ  12,849,573,888 バイトの空き領域
```

JOBIDを引数に指定してgetJobDDs_JobIDを実行すると、カレント・ディレクトリにDD毎に分かれたJOBLOGが取得されます。

一旦USS上(SSH接続ユーザーのホーム・ディレクトリ)にファイルが作成されますので、大きいJOBLOG扱う場合はファイルシステムの空き容量に注意して下さい。

##JOB名指定でJOBLOG取得

上と同様の要領で、JOBIDではなくJOB名指定でJOBLOG取得するバッチです。

```bat:getJobDDs_JobName.bat
@echo off
setlocal enabledelayedexpansion

if "%sdsf_host%" == "" (
	set sdsf_host="ePlex"
) 

if "%sdsf_user%" == "" (
	set sdsf_user="CICS004"
)

set tempJobDDsListFile=tempJobDDsList.txt

ssh %sdsf_user%@%sdsf_host% . ./.profile; getJobDDs.sh "%1" > %tempJobDDsListFile%

FOR /F "tokens=1,2,3*" %%a IN (%tempJobDDsListFile%) do (
	scp %sdsf_user%@%sdsf_host%:%%c ./
	ssh %sdsf_user%@%sdsf_host% . ./.profile; rm %%c
)

REM del %tempJobDDsListFile%
```

利用しているUSS上のスクリプトが違うだけです。(jobdd.rex => getJobDD.sh)
JOB名を引数に指定すると、そのJOB名に合致するJOBのうち一番IDが大きいもの(≒最新のもの)を入手します。

```xxx:実行例
c:\y\temp\zos>getJobDDs_JobName LISTC
JOB04888_JESMSGLG.txt                                                  100% 1346     1.3KB/s   00:00
JOB04888_JESJCL.txt                                                    100%  625     0.6KB/s   00:00
JOB04888_JESYSMSG.txt                                                  100%  896     0.9KB/s   00:00
JOB04888_SYSPRINT.txt                                                  100%   60KB  59.9KB/s   00:00

c:\y\temp\zos>dir
 ドライブ C のボリューム ラベルがありません。
 ボリューム シリアル番号は 2A67-11E4 です

 c:\y\temp\zos のディレクトリ

2016/09/26  11:42    <DIR>          .
2016/09/26  11:42    <DIR>          ..
2016/09/26  20:34               625 JOB04888_JESJCL.txt
2016/09/26  20:34             1,346 JOB04888_JESMSGLG.txt
2016/09/26  20:34               896 JOB04888_JESYSMSG.txt
2016/09/26  20:34            61,323 JOB04888_SYSPRINT.txt
2016/09/26  20:34               142 tempJobDDsList.txt
               5 個のファイル              64,332 バイト
               2 個のディレクトリ  12,848,582,656 バイトの空き領域

```

#USSアクセス汎用バッチ
z/OSのUSSに対してssh経由でコマンドを実行する汎用的なバッチを用意しておけば、それで任意のREXXとかシェル・スクリプトとかコマンドとか直接実行できちゃいます。

uss.batという汎用的なバッチを作ります。

```bat:uss.bat
@echo off
setlocal enabledelayedexpansion

if "%sdsf_host%" == "" (
	set sdsf_host="ePlex"
) 

if "%sdsf_user%" == "" (
	set sdsf_user="CICS004"
)

ssh %sdsf_user%@%sdsf_host% . ./.profile;"%1"
```

例えば...

```xxx:使用例1
c:\y\temp\zos>uss "jcl_sub.sh 'CICSSHR.CICS004.JCLLIB\(LISTC\)' " > listc.txt
```

これは、USS上のjcl_sub.shを使用してJCLをサブミットしている例です。括弧「(」、「)」はエスケープする必要があるので直前にバックスラッシュを指定する必要があります。
実行後のJOBLOGは標準出力に返されますが、上の例ではlistc.txtというテキストファイルにリダイレクトしています。
つまり、Windowsから一発でJCL実行してJOBLOGもWindows上のファイルに書き出される、ということになります。いい感じですねぇ。
JCLのサブミットもWindowsから頻繁に実施するという場合には、先の例にならって専用バッチを作ってもよいでしょう。

```xxx:使用例2
c:\y\temp\zos>uss "tsocmd listuser"
listuser
USER=CICS004  NAME=CICS004               OWNER=IBMUSER   CREATED=02.129
 DEFAULT-GROUP=ESA      PASSDATE=16.264 PASS-INTERVAL= 30 PHRASEDATE=N/A
 ATTRIBUTES=SPECIAL OPERATIONS
 REVOKE DATE=NONE   RESUME DATE=NONE
 LAST-ACCESS=16.270/20:50:51
 CLASS AUTHORIZATIONS=NONE
 NO-INSTALLATION-DATA
 NO-MODEL-NAME
 LOGON ALLOWED   (DAYS)          (TIME)
 ---------------------------------------------
 ANYDAY                          ANYTIME
  GROUP=ESA       AUTH=USE      CONNECT-OWNER=IBMUSER   CONNECT-DATE=02.129
    CONNECTS=11,128  UACC=NONE     LAST-CONNECT=16.270/20:50:51
    CONNECT ATTRIBUTES=NONE
    REVOKE DATE=NONE   RESUME DATE=NONE
SECURITY-LEVEL=NONE SPECIFIED
CATEGORY-AUTHORIZATION
 NONE SPECIFIED
SECURITY-LABEL=NONE SPECIFIED
TMP attach failure -1720
```

これはUSS上の```tsocmd```というコマンドを使ってlistuserというTSOコマンドを実行している例です。
出力をファイルにリダイレクトすれば、TSOコマンドの結果を簡単にWindowsファイルに落とすこともできますね。

#おわりに
「SSH公開鍵認証 + USS REXX/シェル・スクリプト + バッチ」で、かなり素敵な環境になると思います。
eclipseだとかブラウザだとかそういうインターフェースもいいですけど、このくらいのCUI環境が当たり前のようにさくっと使えるようにしておいて欲しいもんです。若者が初めてz/OSに触れる際のハードルもぐっと下がると思うんですけどねぇ。