VSCodeを使用したメインフレーム・アプリケーション開発 - (6)FTP経由での接続

# はじめに
これまでの記事では、z/OS側にはz/OSMFをセットアップしVS Codeとz/OSMFの接続をベースにして各種操作を行うやり方を見てきました。しかし、z/OSを比較的小規模で使用している場合などではz/OSMFを立てることにハードルがあるケースもあるようです。z/OSMFは実体としてはLibertyなのでzIIPオフロード対象になりますが、zIIPが搭載されていない場合もあると思います。
VS Codeとの連携についてはz/OSMFやRSEを使う接続方法以外にFTPを利用するという方法もあります。機能は限定的になりますがFTP接続でどの辺りのことができるのかをやってみます。
ここに記載している内容はいずれも追加のライセンスコスト無しで実施できるものです。

## 関連記事
[VSCodeを使用したメインフレーム・アプリケーション開発 - (1)概要](https://qiita.com/tomotagwork/items/085b91098fce3aabaeaf)
[VSCodeを使用したメインフレーム・アプリケーション開発 - (2)z/OS基本操作](https://qiita.com/tomotagwork/items/9496dbc121cc5bf17b29)
[VSCodeを使用したメインフレーム・アプリケーション開発 - (3)ソース編集](https://qiita.com/tomotagwork/items/f4008d1ead61e8a263ae)
[VSCodeを使用したメインフレーム・アプリケーション開発 - (4)ソース管理ツール/ビルドツール連携](https://qiita.com/tomotagwork/items/4bdd0b5a7284b5102d10)
[VSCodeを使用したメインフレーム・アプリケーション開発 - (5)デバッガーの利用](https://qiita.com/tomotagwork/items/2ce806f5747bc72f9474)
[VSCodeを使用したメインフレーム・アプリケーション開発 - (6)FTP経由での接続](https://qiita.com/tomotagwork/items/a2f82db16d18a8fd9d21)

# セットアップ

## 全体像
z/OS側は基本的にはFTPサーバーが稼働してFTPが使える状態であればOKです。
VS Code側には、Zowe CLIのプラグインである「IBM z/OS FTP Plug-in for Zowe CLI」、および、VS CodeのExtensionとして「Zowe Explorer FTP Extension」をインストールして使用します。

構成のイメージとしては以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/7f37c504-47a8-2a49-194f-c16857ae1e8a.png)

参考:
[IBM z/OS FTP Plug-in for Zowe CLI](https://docs.zowe.org/stable/user-guide/cli-ftpplugin/)
[Using Zowe Explorer FTP Extension](https://docs.zowe.org/stable/user-guide/ze-ftp/)

## z/OS側コンポーネント

基本的にはFTPDが稼働していてFTPクライアントから使用できればよいですが、前提条件としてFTPのパラメーター"JESINTERFACELEVEL"を"2"に設定しておく必要があります(デフォルトは1)。このパラメーターはFTP経由でJESにアクセスする際の制御方法を指定するものです。
参考: [JESINTERFACELEVEL (FTP server) statement](https://www.ibm.com/docs/en/zos/2.4.0?topic=protocol-jesinterfacelevel-ftp-server-statement)

このパラメーターはFTP起動プロシージャーのSYSFTPD DDなどで指定されます。
参考: [FTP configuration statements in FTP.DATA](https://www.ibm.com/docs/en/zos/2.4.0?topic=protocol-ftp-configuration-statements-in-ftpdata)

起動プロシージャー例

```CPAC.PROCLIB(FTPD)
//FTPD   PROC MODULE='FTPD',PARMS=''                                             
//*********************************************************************          
//FTPD   EXEC PGM=&MODULE,REGION=4096K,TIME=NOLIMIT,          
//       PARM='/&PARMS'                                       
//CEEDUMP  DD SYSOUT=*  
//SYSFTPD  DD DISP=SHR,                    
//        DSN=TCPIVP.TCPPARMS(FTPSDATA)    
//SYSTCPD  DD DISP=SHR,                 
//        DSN=TCPIVP.TCPPARMS(TCPDATA)  
//*  
```

構成パラメーター例

```TCPIVP.TCPPARMS(FTPSDATA)抜粋
...
; ---------------------------------------------------------------------
;
; 9. JES interface options
;
; ---------------------------------------------------------------------

 JESLRECL          80            ; (S) Lrecl of jobs submitted to JES.
                                     ; Default value is 80.
                                     ; Valid range from 1 through 254.

 JESPUTGETTO       600               ; Number of seconds in JesPutGet
                                     ; state (number of seconds server
                                     ; will wait between submitting a
                                     ; job and retrieving its output.
                                     ; Default value is 600 seconds.
                                     ; Valid range 0 through 86400.

 JESRECFM          F             ; (S) Recfm of jobs submitted to JES.
                                     ; F = Fixed length (D)
                                     ; V = Variable length (use only
                                     ;     with JES3 systems)
                                     ; * = Use record format specified
                                     ;     on the RECFM statement

 JESINTERFACELEVEL 2                 ; Functional level of the JES
                                     ; interface
                                     ; 1 = Interface works as it did
                                     ;     prior to OS/390 V2R10 (D)
                                     ; 2 = Interface works according
                                     ;     to the enhanced support
                                     ;     in OS/390 V2R10
...

```


FTPクライアントからFTP接続して、"quote stat"コマンドで設定値を確認することも可能です。

WindowsのFTPクライアントから設定値を確認する例

```
C:\Users\TomohiroTaguchi>ftp MLZSYS
MLZSYS に接続しました。
220-FTP Server (user 'xxx')
220
500-Syntax error -- unknown command
500
ユーザー (MLZSYS:(none)): TAGUCHI
331-Password:
331
パスワード:
230-220-FTPD1 IBM FTP CS V2R3 at xxx, 03:19:43 on 2022-05-01.
230-TAGUCHI is logged on.  Working directory is "TAGUCHI.".
230
ftp> quote stat
211-Server FTP talking to host xxx, port 50300
211-User: TAGUCHI  Working directory: TAGUCHI.
211-The control connection has transferred 122 bytes
211-There is no current data connection.
211-The next data connection will be actively opened
211-to host xxx, port 50300,
211-using Mode Stream, Structure File, type ASCII, byte-size 8
211-Automatic recall of migrated data sets.
211-Automatic mount of direct access volumes.
211-Auto tape mount is allowed.
211-Inactivity timer is set to 300
211-Timer FTPKEEPALIVE is set to 0
211-Timer DATAKEEPALIVE is set to 0
211-Timer DSWAITTIME is set to 0
211-Server site variable DSWAITTIMEREPLY is set to 60
211-Timer FIFOOPENTIME is set to 60
211-Timer FIFOIOTIME is set to 20
211-VCOUNT is 59
211-ASA control characters in ASA files opened for text processing will be
211- transferred as ASA control characters.
211-Server site variable TAPEREADSTREAM is set to FALSE
211-Trailing blanks are removed from a fixed format data set when it is
211- retrieved.
211-Data set mode.  (Do not treat each qualifier as a directory.)
211-ISPFSTATS is set to FALSE
211-Primary allocation 1 track.  Secondary allocation 1 track.
211-Partitioned data sets will be created with 27 directory blocks.
211-FileType SEQ (Sequential - default).
211-Number of access method buffers is 5
211-RDWs from variable format data sets are discarded.
211-Records on input tape are unspecified format
211-SITE DB2 subsystem name is DB2
211-Data not wrapped into next record.
211-Tape write is not allowed to use BSAM I/O
211-Truncated records will be treated as an error and the file transfer will
211- fail
211-JESLRECL is 80
211-JESRECFM is Fixed
211-JESINTERFACELEVEL is 2
211-Server site variable JESTRAILINGBLANKS is set to TRUE
211-Confidence level in data transfers is neither checked nor reported
211-ENcoding is set to SBCS
211-Outbound SBCS ASCII data uses CRLF line terminator
211-Outbound MBCS ASCII data uses CRLF line terminator
211-Server site variable MBREQUIRELASTEOL is set to TRUE
211-Server site variable UNICODEFILESYSTEMBOM is set to ASIS
211-Server site variable UNIXFILETYPE is set to FILE
211-DBSUB is set to FALSE
211-Server site variable EXTDBSCHINESE is set to TRUE
211-SBSUB is set to FALSE
211-SBSUBCHAR is set to SPACE
211-SMS is active.
211-New data sets will be catalogued if a store operation ends abnormally
211-Single quotes will override the current working directory.
211-UMASK value is 027
211-Process id is 67120330
211-Checkpoint interval is 0
211-Server site variable RESTPUT is set to TRUE
211-Server site variable REMOVEINBEOF is set to FALSE
211-Authentication type: None
211-TLS security is supported at the DRAFT level
211-Server site variable READVB is set to LE
211-Port of Entry resource class for IPv4 clients is: TERMINAL
211-Record format VB, Lrecl: 256, Blocksize: 6233
211-Server site variable EATTR is set to SYSTEM
211-Server site variable DSNTYPE is set to SYSTEM
211-Server site variable LISTSUBDIR is set to TRUE
211-Server site variable LISTLEVEL is set to 0
211 *** end of status ***
```

ちょうど真ん中あたりに`211-JESINTERFACELEVEL is 2`というのが出力されているのが確認できます。

## VS Code側コンポーネント

node, VS Code, Zowe CLIなどはインストール済みとします。

### IBM z/OS FTP Plug-in for Zowe CLIのインストール
参考: [z/OS FTP Plug-in for Zowe CLI](https://github.com/zowe/zowe-cli-ftp-plugin)

```
c:\>node --version
v16.15.0

c:\>zowe plugins install @zowe/zos-ftp-for-zowe-cli@latest
Plug-ins within the Imperative CLI Framework can legitimately gain
control of the zowe CLI application during the execution of every command.
Install 3rd party plug-ins at your own risk.

Registry = https://registry.npmjs.org/

_______________________________________________________________
npm WARN @zowe/zos-ftp-for-zowe-cli@2.0.0 requires a peer of @zowe/imperative@^5.0.0 but none is installed. You must install peer dependencies yourself.

Installed plugin name = '@zowe/zos-ftp-for-zowe-cli'

_____ Validation results for plugin '@zowe/zos-ftp-for-zowe-cli' _____
This plugin was successfully validated. Enjoy the plugin.
```

Warning出てるけどインストール成功しているのでそのまま進みます。

一応インストールされているZowe CLIのプラグインを確認。

```
c:\>zowe plugins list

Installed plugins:

 -- pluginName: @ibm/rse-api-for-zowe-cli
 -- package: @ibm/rse-api-for-zowe-cli
 -- version: 1.2.5
 -- registry: https://registry.npmjs.org/

 -- pluginName: @zowe/secure-credential-store-for-zowe-cli
 -- package: @zowe/secure-credential-store-for-zowe-cli@zowe-v1-lts
 -- version: 4.1.5
 -- registry: https://registry.npmjs.org/

 -- pluginName: @zowe/zos-ftp-for-zowe-cli
 -- package: @zowe/zos-ftp-for-zowe-cli@latest
 -- version: 2.0.0
 -- registry: https://registry.npmjs.org/
```


### Using Zowe Explorer FTP Extensionのインストール

VS Codeを開いてMarketplaceから"Zowe Explorer Extension for FTP"を検索しインストール。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/cf41ab65-2035-71f6-e816-4be3f9e79201.png)

## Zowe CLI接続構成

参考: [Zowe CLI Reference - zowe › profiles › create › zftp-profile](https://docs.zowe.org/stable/web_help/index.html?p=zowe_profiles_create_zftp-profile)

FTP経由で接続するためのZowe CLIプロファイル "ZFTPプロファイル" を作成します。

```
c:\>zowe profiles create zftp zftp-MLZSYS -H MLZSYS -u TAGUCHI -p xxx -P 21 --secure-ftp false
Profile created successfully! Path:
C:\Users\TomohiroTaguchi\.zowe\profiles\zftp\zftp-MLZSYS.yaml

host:              MLZSYS
port:              21
user:              managed by @zowe/secure-credential-store-for-zowe-cli
password:          managed by @zowe/secure-credential-store-for-zowe-cli
secureFtp:         false
connectionTimeout: 10000

Review the created profile and edit if necessary using the profile update command.

Warning: The command 'profiles create' is deprecated.
Recommended replacement: The 'config init' command
```

※profiles createコマンドはdeprecatedになってるみたいですね。zowe cliのコマンド体系も変更されつつあるようです...。今回はこのまま進めます。
※デフォルトでは--secure-ftp trueになるので、明示的にfalseを指定しています。--secure-ftp true指定の場合、FTPS(FTP over SSL)の設定が必要になります。ここでは通常のFTPを使用する想定です。

追加したProfileが有効かどうか、FTPのCLIを試してみます。
参考: [Zowe CLI Reference - zowe › zos-ftp](https://docs.zowe.org/stable/web_help/index.html?p=zowe_zos-ftp)

```
c:\>zowe zos-ftp list data-set "SYS1.P*LIB" --zftp-profile zftp-MLZSYS
SYS1.PARMLIB
SYS1.PDEFLIB
SYS1.PROCLIB
SYS1.PSEGLIB
```

OKです。

## VS Codeにプロファイル追加

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/af04374c-8853-eb85-980c-003c7ca5983b.png)

上で作成したZFTPプロファイルをVS Code上に登録して使用します。

DATA SETSにFTP用のプロファイルを追加すれば、FTP経由でデータセットにアクセスしてソース編集などが行えるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/9d54fec6-a995-547b-148e-7b823badee4b.png)

同様に、USS, JOBS以下にプロファイルを追加すれば、USS上のファイル、JOBLOGなどを確認することもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/dda75aae-d565-7568-bad2-3adf340dbf63.png)

# 操作についての考察

COBOLのソース(PDSメンバー)を開いて編集する、JCLをサブミットしてJOBLOGを確認する、といった基本的な操作はFTP経由のプロファイルを使っても行えることは確認できました。しかし、このプロファイルを使ってできる操作というのは、内部的にはFTPを使っていますのでFTPでできる範囲の操作に限定されてしまうようです。全ての機能を逐一確認したわけではありませんが、気づいた点について記載しておきます。

## できること
まず、この辺の操作は一応行えました。

- PDSメンバーの参照、編集
- USS上のファイル参照、編集(EBCDICの場合)
- COBOL, REXX, JCLなどをエディターで開いた時の構文解析(色分け表示)、コンテンツアシスト等
- file association設定(「**COBOLデータセットに含まれるメンバーはCOBOLソースとみなす」といったマッピング)
- JCLサブミット
- JOBLOG確認

参考: [Setting file associations](https://ibm.github.io/zopeneditor-about/Docs/setting_fileassociations.html#local-file-associations)

## できないこと

- PDSメンバーのコピー
- Allocate Like (New Data Set with Same Attributes): 特定のデータセットの属性をコピーして別のデータセットを作成する
- propertygroups設定(※1)
- MVSコマンド実行

※1補足
参考: [Setting property groups](https://ibm.github.io/zopeneditor-about/Docs/setting_propertygroup.html#setting-property-groups)
COBOL,PL/Iでは、COPY,INCLUDE で別メンバーとして定義された変数定義情報をソース中に取り込むということをよくやります。例えば、COBOLソースをVS Codeのエディターで開いてCOPY句に指定したメンバー名にカーソルを当てるとそのメンバー名の中身をポップアップで表示してくれる機能があります。このメンバーの探索先は設定ファイルのpropertygroupsというパラメータに設定しておく必要があります。ただし、このpropertygroupsで指定できるのは基本的にデータセットのパターンで、接続先z/OSは指定できません。この接続先のz/OSがどのように選択されるかというと、"defaultCliProfile"というプロパティーで指定されたデフォルトプロファイルに紐づくz/OSを見に行くことになります。この"defaultCliProfile"にはz/OSMFプロファイル、もしくはRSEプロファイルしか指定できず、ZFTPプロファイルは指定できません。

>MVS property groups using Zowe profiles
If you have Zowe CLI or Zowe Explorer configured on your development machine, property groups of type MVS will try to resolve copybooks referenced in COBOL programs using your Zowe default RSE or z/OSMF service profile. 
...
The value of defaultCliProfile is the name of the Zowe RSE or z/OSMF profile that you want to use. (In the example above, it is "rseCLI".)

結論として、ZFTPプロファイルとして定義したz/OS上のデータセットをCOPY句の探索先として指定することはできない、つまり、ZFTPプロファイル経由でCOBOLソースを編集する場合、MVS上のCOPY句を直接探索させることはできない、ということになります。

ちなみに...
COPY句探索先としてはz/OS上のデータセットを指定する方法と、ローカルのディレクトリを指定する方法があります。上の制約はz/OS上のデータセットからCOPY句を探索する場合の制約となります。z/OS上のソースを直接編集するのではなく、ソースをGitで管理してCOPY句含めて一旦ローカルに持ってきてソースを編集するシナリオの場合であればCOPY句探索先もローカルのディレクトリになるので、プラグインの種類に関係なくCOPY句内容のポップアップ参照は利用可能です(ローカルでの編集においてはz/OSとの接続は関係ないので接続プロトコルの種類に依存しません)。


## その他考慮点

### 文字コード変換
文字コード変換は完全にFTPの構成に依存して一意に決まることになります。z/OSMF接続に比べると柔軟な文字コード変換の制御は出来ないと思われますのでご注意ください。
詳細はz/OSのFTP関連のドキュメントをご参照ください。

### 編集の競合
z/OSMF経由の接続の場合、編集操作が競合した場合以下のような制御が行われていました。
参考: [ファイルの排他制御について](https://qiita.com/tomotagwork/items/9496dbc121cc5bf17b29#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E6%8E%92%E4%BB%96%E5%88%B6%E5%BE%A1%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

z/OSMF接続の場合、編集の競合が生じると上のようにソースの比較をしたり強制上書きが選択できたりしますが、ZFTP経由の場合はそこまで柔軟な対応ができないようです。VS Codeで編集して競合を検知した場合、以下のエラーが出るだけで、保存ができない状態になります。
`Zowe Explorer FTP Extension: Save conflict. Please pull the latest content from mainframe first.`
従って、このように競合が発生してしまった場合は一旦編集した内容を破棄して最新の情報を取得し直してから再度編集する、という操作を行う必要があります。