はじめに
先の記事では、まず基本となる構成や単純なPlaybookを動かすところまでをやってみました。まずシンプルなPlaybookとしてMVSコマンドを投入するということをやってみましたが、他にも各種z/OS管理機能がAnsibleモジュールとして提供されています。
ここでは、z/OS Core Collectionで提供されるz/OS操作に関するモジュールを使ってどんなことができるのかを見ていきたいと思います。
関連記事
Ansibleを用いたz/OSカスタマイズ自動化 - (1) 概要/基本構成
Ansibleを用いたz/OSカスタマイズ自動化 - (2) z/OS Core Collectionを試す
Ansibleを用いたz/OSカスタマイズ自動化 - (3) Ansible提供モジュールを試す
Ansibleを用いたz/OSカスタマイズ自動化 - (4) 雑多な考察
Tips
モジュールの動作をトライ&エラーを繰り返して確認していく際には、デフォルトの設定だとPlaybook実行結果がかなり分かりにくいと感じることが多々あります。
参考:Ansible Tips: taskがエラーとなった場合などの結果出力を劇的に読みやすくする設定(stdout_callback = debug)
上の記事で紹介されている設定をするとかなり出力結果がみやすくなるのでおすすめです。
具体的には、ansible.cfgにて以下の設定を行います。
[defaults]
...
verbosity = 1
stdout_callback = ansible.posix.debug
verbosity = 1'指定により成功時にも詳細出力結果が表示されるようになり、かつ
stdout_callback = ansible.posix.debug`指定により出力結果がフォーマットされたJSON形式となります。
この機能を使用する際は前提として ansible.posix コレクションをインストールしておく必要があります。
参考:
ansible.posix.debug callback – formatted stdout/stderr display
ANSIBLE_VERBOSITY
※当記事の結果は基本的には上の設定を行った環境での例を記載しています。
z/OS Core Collection提供のモジュールを試す
ここでは具体的なオペレーションの例をあげてそれがz/OS Core Collectionで提供されるモジュールを使用してどのようにPlaybookを実装できるのかを見ていきたいと思います。
0.MVSコマンド実行
単純なMVSコマンド実行は前回の記事で実施してみたのでそちらを参照
→ サンプルPlaybook
1.TSOコマンド実行
zos_tso_commandというモジュールを使用してTSOコマンドを実行してみたいと思います。
ここではLISTCAT ENTRIES(xxx)
というコマンドを例にやってみます。
※User Catalog作成前に存在チェックをする目的でこのコマンドを利用することを想定しています。
参考:USS上のシェルからtsocmd経由で実行した時の例
コマンド成功例 (存在するEntryを指定)
IBMUSER : /u/ibmuser : > tsocmd "LISTCAT ENTRIES('CATALOG.VS01.TSO')"
LISTCAT ENTRIES('CATALOG.VS01.TSO')
USERCATALOG --- CATALOG.VS01.TSO
IN-CAT --- CATALOG.VS01.MASTER
コマンド失敗例 (存在しないEntryを指定)
IBMUSER : /u/ibmuser : > tsocmd "LISTCAT ENTRIES('CATALOG.TEST01')"
LISTCAT ENTRIES('CATALOG.TEST01')
IDC3012I ENTRY CATALOG.TEST01 NOT FOUND+
IDC3009I ** VSAM CATALOG RETURN CODE IS 8 - REASON CODE IS IGG0CLEG-42
IDC1566I ** CATALOG.TEST01 NOT LISTED
IDC0014I LASTCC=4
上のようなTSOコマンドをAnsibleのPlaybookで実行してみます。
コマンド成功例 (存在するEntryを指定)
- name: check user catalog
hosts: ezdwazi04
environment: "{{ environment_vars }}"
vars:
ucatName: "CATALOG.VS01.TSO"
#ucatName: "CATALOG.TEST01"
gather_facts: no
tasks:
- name: check user catalog
ibm.ibm_zos_core.zos_tso_command:
commands:
- LISTCAT ENTRIES('{{ ucatName }}')
register: tmp_result
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_check_ucat_test01.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [check user catalog] ***************************************************************************************************************************************************************************************
TASK [check user catalog] ***************************************************************************************************************************************************************************************
changed: [ezdwazi04] => {
"changed": true,
"max_rc": 0,
"output": [
{
"command": "LISTCAT ENTRIES('CATALOG.VS01.TSO')",
"content": [
"USERCATALOG --- CATALOG.VS01.TSO",
" IN-CAT --- CATALOG.VS01.MASTER",
""
],
"failed": false,
"lines": 3,
"rc": 0,
"stderr": ""
}
]
}
PLAY RECAP ******************************************************************************************************************************************************************************************************
ezdwazi04 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
コマンド失敗例 (存在しないEntryを指定)
- name: check user catalog
hosts: ezdwazi04
environment: "{{ environment_vars }}"
vars:
#ucatName: "CATALOG.VS01.TSO"
ucatName: "CATALOG.TEST01"
gather_facts: no
tasks:
- name: check user catalog
ibm.ibm_zos_core.zos_tso_command:
commands:
- LISTCAT ENTRIES('{{ ucatName }}')
register: tmp_result
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_check_ucat_test01.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [check user catalog] ***************************************************************************************************************************************************************************************
TASK [check user catalog] ***************************************************************************************************************************************************************************************
fatal: [ezdwazi04]: FAILED! => {
"changed": false,
"max_rc": 0,
"output": [
{
"command": "LISTCAT ENTRIES('CATALOG.TEST01')",
"content": [
"IDC3012I ENTRY CATALOG.TEST01 NOT FOUND+",
"IDC3009I ** VSAM CATALOG RETURN CODE IS 8 - REASON CODE IS IGG0CLEG-42",
"IDC1566I ** CATALOG.TEST01 NOT LISTED",
"IDC0014I LASTCC=4",
""
],
"failed": true,
"lines": 5,
"rc": 4,
"stderr": ""
}
]
}
MSG:
Some (True) command(s) failed:
Command "LISTCAT ENTRIES('CATALOG.TEST01')" executionfailed. RC was 4.
PLAY RECAP ******************************************************************************************************************************************************************************************************
ezdwazi04 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
さて、次にこのTSOコマンドの結果をPlaybook上でハンドリングしてみたいと思います。
※User Catalogが存在していなかった場合にのみ作成するなどの判断を行うことを想定します。
- name: check user catalog
hosts: ezdwazi04
environment: "{{ environment_vars }}"
vars:
#ucatName: "CATALOG.VS01.TSO"
ucatName: "CATALOG.TEST01"
gather_facts: no
tasks:
- name: check user catalog
ibm.ibm_zos_core.zos_tso_command:
commands:
- LISTCAT ENTRIES('{{ ucatName }}')
register: tmp_result
ignore_errors: yes
- name: display results 1
debug:
msg: "result: {{ tmp_result }} "
- name: display results 2
debug:
msg: "output: {{ tmp_result['output'] }}"
- name: display results 3
debug:
msg: "rc: {{ tmp_result.output[0].rc }} / stderr: {{ tmp_result.output[0].stderr }} / failed: {{ tmp_result.output[0].failed }} "
- name: define user catalog when it does not exist
debug:
msg: "*** define user catalog ***"
when: tmp_result.output[0].failed == True
Playbook補足:
- TSOコマンド実行のタスク(check user catalog)に、
ignore_errors: yes
を追加で指定しています。コマンドがエラーになるとデフォルトではPlaybook自体の処理が終了して後続タスクが実行されません。後続タスクでエラー時の判断をするためにこの指定をしてエラーを無視して処理継続できるようにしています。 - display results 1~3 のタスクを指定して、TSOコマンド結果を保持した変数
tmp_result
の内容をいくつかのパターンで表示しています。 - 最後のタスクでは、
when
を用いてTSOコマンド結果の成否を判断し、失敗した場合のみメッセージを出力させているということやっています。
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_check_ucat_test02.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [check user catalog] ***************************************************************************************************************************************************************************************
TASK [check user catalog] ***************************************************************************************************************************************************************************************
fatal: [ezdwazi04]: FAILED! => {
"changed": false,
"max_rc": 0,
"output": [
{
"command": "LISTCAT ENTRIES('CATALOG.TEST01')",
"content": [
"IDC3012I ENTRY CATALOG.TEST01 NOT FOUND+",
"IDC3009I ** VSAM CATALOG RETURN CODE IS 8 - REASON CODE IS IGG0CLEG-42",
"IDC1566I ** CATALOG.TEST01 NOT LISTED",
"IDC0014I LASTCC=4",
""
],
"failed": true,
"lines": 5,
"rc": 4,
"stderr": ""
}
]
}
MSG:
Some (True) command(s) failed:
Command "LISTCAT ENTRIES('CATALOG.TEST01')" executionfailed. RC was 4.
...ignoring
TASK [display results 1] ****************************************************************************************************************************************************************************************
ok: [ezdwazi04] => {}
MSG:
result: {'changed': False, 'failed': True, 'output': [{'command': "LISTCAT ENTRIES('CATALOG.TEST01')", 'rc': 4, 'content': ['IDC3012I ENTRY CATALOG.TEST01 NOT FOUND+', 'IDC3009I ** VSAM CATALOG RETURN CODE IS 8 - REASON CODE IS IGG0CLEG-42', 'IDC1566I ** CATALOG.TEST01 NOT LISTED', 'IDC0014I LASTCC=4', ''], 'lines': 5, 'stderr': '', 'failed': True}], 'max_rc': 0, 'msg': 'Some (True) command(s) failed:\nCommand "LISTCAT ENTRIES(\'CATALOG.TEST01\')" executionfailed. RC was 4.'}
TASK [display results 2] ****************************************************************************************************************************************************************************************
ok: [ezdwazi04] => {}
MSG:
output: [{'command': "LISTCAT ENTRIES('CATALOG.TEST01')", 'rc': 4, 'content': ['IDC3012I ENTRY CATALOG.TEST01 NOT FOUND+', 'IDC3009I ** VSAM CATALOG RETURN CODE IS 8 - REASON CODE IS IGG0CLEG-42', 'IDC1566I ** CATALOG.TEST01 NOT LISTED', 'IDC0014I LASTCC=4', ''], 'lines': 5, 'stderr': '', 'failed': True}]
TASK [display results 3] ****************************************************************************************************************************************************************************************
ok: [ezdwazi04] => {}
MSG:
rc: 4 / stderr: / failed: True
TASK [define user catalog when it does not exist] ***************************************************************************************************************************************************************
ok: [ezdwazi04] => {}
MSG:
*** define user catalog ***
PLAY RECAP ******************************************************************************************************************************************************************************************************
ezdwazi04 : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
TSOコマンド実行し、その結果によって処理を制御する基本的なやり方が確認できました。
2.Jinja2テンプレートを使用したJCL実行
zos_job_submit というモジュールを使います。
AnsibleにはJinja2テンプレートという仕組みが合って、スクリプトや各種構成ファイルなどをテンプレートとして作成しておき、一部の内容を環境に応じて動的に変更して利用することができます。
ここでは、JCLをJinja2テンプレートとして作成しておき、一部のパラメーターを環境変数で与えて実行する、ということをやってみます。
テンプレートとなるJCLを作成:
//LISTC JOB MSGCLASS=X,CLASS=A
//*-----------------------------------------------------
//*
//GO EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
LISTCAT ENTRIES({{ listcEntryName }})
/*
templateというディレクトリ下に上のようなjCLのテンプレートを作成します。上の例はIDCAMSユーティリティでLISTCATを実行する単純なJCLです。
LISTCAT ENTRIES(xxx)
のxxx部分を変数に置き換えています。このようにJinja2の作法に従って動的に文字列を置き換えるための記述が行えます(if分を用いた複雑な条件分岐なども利用できます)。
上のtemplateを使用してJCLをSubmitするためのPlaybookを作成します。
- name: submit a JCL
hosts: ezdwazi04
environment: "{{ environment_vars }}"
gather_facts: no
vars:
jclName: "listc.jcl"
listcEntryName: "CATALOG.VS01.TSO"
#listcEntryName: "CATALOG.TEST01"
#listcEntryName: "TTTTTTTTTTTTTTT"
tasks:
- name: submit JCL
ibm.ibm_zos_core.zos_job_submit:
src: "./templates/{{ jclName }}"
location: LOCAL
encoding:
from: UTF-8
to: IBM-037
use_template: true
wait_time_s: 10
register: jcl_result
ignore_errors: yes
- name: display results when rc > 4
debug:
msg: "Result: {{ jcl_result.jobs[0].job_id }} / {{ jcl_result.jobs[0].ret_code }}"
when: jcl_result.jobs[0].ret_code.code > 4
ここでは、JCLがRC=0で正常終了する場合、RC=4でエラーになる場合、RC=12でエラーになる場合の結果を見てみます。
JCLがRC=0で終了する例 (存在するEntryを指定)
実行例
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_jcl_listc_test01.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [submit a JCL] *********************************************************************************************************************************************************************************************
TASK [submit JCL] ***********************************************************************************************************************************************************************************************
changed: [ezdwazi04] => {
"changed": true,
"dest": "/tmp/ansible.zbtbqktz",
"duration": 1,
"gid": 0,
"group": "SYS1",
"is_binary": false,
"jobs": [
{
"asid": "0",
"class": "A",
"content_type": "",
"creation_date": "2024-03-31",
"creation_time": "1:38:47",
"ddnames": [
{
"byte_count": "133",
"content": [
"1 J E S 2 J O B L O G -- S Y S T E M V S 0 1 -- N O D E N 1",
"0 ",
" 01.38.47 JOB00283 ---- SUNDAY, 31 MAR 2024 ----",
" 01.38.47 JOB00283 IRR010I USERID IBMUSER IS ASSIGNED TO THIS JOB.",
" 01.38.47 JOB00283 ICH70001I IBMUSER LAST ACCESS AT 01:38:46 ON SUNDAY, MARCH 31, 2024",
" 01.38.47 JOB00283 $HASP373 LISTC STARTED - INIT 6 - CLASS A - SYS VS01",
" 01.38.47 JOB00283 IEF403I LISTC - STARTED - TIME=01.38.47",
" 01.38.47 JOB00283 IEF404I LISTC - ENDED - TIME=01.38.47",
" 01.38.47 JOB00283 $HASP395 LISTC ENDED - RC=0000",
"0------ JES2 JOB STATISTICS ------",
"- 31 MAR 2024 JOB EXECUTION DATE",
"- 8 CARDS READ",
"- 66 SYSOUT PRINT RECORDS",
"- 0 SYSOUT PUNCH RECORDS",
"- 7 SYSOUT SPOOL KBYTES",
"- 0.00 MINUTES EXECUTION TIME"
],
"ddname": "JESMSGLG",
"id": "2",
"proctep": null,
"record_count": "16",
"stepname": "JES2"
},
{
"byte_count": "136",
"content": [
" 1 //LISTC JOB MSGCLASS=X,CLASS=A JOB00283",
" //*-----------------------------------------------------",
" //*"
],
"ddname": "JESJCL",
"id": "3",
"proctep": null,
"record_count": "3",
"stepname": "JES2"
},
{
"byte_count": "137",
"content": [
" ICH70001I IBMUSER LAST ACCESS AT 01:38:46 ON SUNDAY, MARCH 31, 2024",
" IEFA111I LISTC IS USING THE FOLLOWING JOB RELATED SETTINGS:",
" SWA=BELOW,TIOT SIZE=64K,DSENQSHR=DISALLOW,GDGBIAS=JOB",
" IEF236I ALLOC. FOR LISTC GO",
" IEF237I JES2 ALLOCATED TO SYSPRINT",
" IEF237I JES2 ALLOCATED TO SYSIN",
" IEF142I LISTC GO - STEP WAS EXECUTED - COND CODE 0000",
" IEF285I IBMUSER.LISTC.JOB00283.D0000102.? SYSOUT",
" IEF285I IBMUSER.LISTC.JOB00283.D0000101.? SYSIN",
" IEF373I STEP/GO /START 2024091.0138",
" IEF032I STEP/GO /STOP 2024091.0138",
" CPU: 0 HR 00 MIN 00.00 SEC SRB: 0 HR 00 MIN 00.00 SEC",
" VIRT: 80K SYS: 312K EXT: 24K SYS: 9880K",
" ATB- REAL: 228K SLOTS: 0K",
" VIRT- ALLOC: 13M SHRD: 0M",
" IEF375I JOB/LISTC /START 2024091.0138",
" IEF033I JOB/LISTC /STOP 2024091.0138",
" CPU: 0 HR 00 MIN 00.00 SEC SRB: 0 HR 00 MIN 00.00 SEC"
],
"ddname": "JESYSMSG",
"id": "4",
"proctep": null,
"record_count": "18",
"stepname": "JES2"
},
{
"byte_count": "125",
"content": [
"1IDCAMS SYSTEM SERVICES TIME: 01:38:47 03/31/24 PAGE 1",
"0 ",
" LISTCAT ENTRIES(CATALOG.VS01.TSO)",
"0USERCATALOG --- CATALOG.VS01.TSO",
" IN-CAT --- CATALOG.VS01.MASTER",
"1IDCAMS SYSTEM SERVICES TIME: 01:38:47 03/31/24 PAGE 2",
"0 THE NUMBER OF ENTRIES PROCESSED WAS:",
" AIX -------------------0",
" ALIAS -----------------0",
" CLUSTER ---------------0",
" DATA ------------------0",
" GDG -------------------0",
" INDEX -----------------0",
" NONVSAM ---------------0",
" PAGESPACE -------------0",
" PATH ------------------0",
" SPACE -----------------0",
" USERCATALOG -----------1",
" TAPELIBRARY -----------0",
" TAPEVOLUME ------------0",
" TOTAL -----------------1",
"0 THE NUMBER OF PROTECTED ENTRIES SUPPRESSED WAS 0",
"0IDC0001I FUNCTION COMPLETED, HIGHEST CONDITION CODE WAS 0",
"0 ",
"0IDC0002I IDCAMS PROCESSING COMPLETE. MAXIMUM CONDITION CODE WAS 0"
],
"ddname": "SYSPRINT",
"id": "102",
"proctep": null,
"record_count": "25",
"stepname": "GO"
}
],
"duration": 1,
"job_class": "A",
"job_id": "JOB00283",
"job_name": "LISTC",
"owner": "IBMUSER",
"priority": "1",
"program_name": "IDCAMS",
"queue_position": "37",
"ret_code": {
"code": 0,
"msg": "CC",
"msg_code": "0000",
"msg_txt": "CC",
"steps": [
{
"step_cc": 0,
"step_name": "GO"
}
]
},
"subsystem": "N1",
"svc_class": "?",
"system": "VS01"
}
],
"mode": "0600",
"owner": "BPXROOT",
"size": 479,
"src": "/u/ibmuser/.ansible/tmp/ansible-tmp-1711863494.0475485-28656-208523992640196/source",
"state": "file",
"uid": 0
}
TASK [display results when rc > 4] ******************************************************************************************************************************************************************************
skipping: [ezdwazi04] => {
"false_condition": "jcl_result.jobs[0].ret_code.code > 4"
}
PLAY RECAP ******************************************************************************************************************************************************************************************************
ezdwazi04 : ok=1 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
JCLがRC=4で終了する例 (存在しないEntryを指定)
実行例
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_jcl_listc_test01.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [submit a JCL] *********************************************************************************************************************************************************************************************
TASK [submit JCL] ***********************************************************************************************************************************************************************************************
fatal: [ezdwazi04]: FAILED! => {
"changed": false,
"dest": "/tmp/ansible.n7mzkj6d",
"duration": 1,
"gid": 0,
"group": "SYS1",
"is_binary": false,
"jobs": [
{
"asid": "0",
"class": "A",
"content_type": "",
"creation_date": "2024-03-31",
"creation_time": "1:41:25",
"ddnames": [
{
"byte_count": "133",
"content": [
"1 J E S 2 J O B L O G -- S Y S T E M V S 0 1 -- N O D E N 1",
"0 ",
" 01.41.25 JOB00285 ---- SUNDAY, 31 MAR 2024 ----",
" 01.41.25 JOB00285 IRR010I USERID IBMUSER IS ASSIGNED TO THIS JOB.",
" 01.41.25 JOB00285 ICH70001I IBMUSER LAST ACCESS AT 01:41:24 ON SUNDAY, MARCH 31, 2024",
" 01.41.25 JOB00285 $HASP373 LISTC STARTED - INIT 6 - CLASS A - SYS VS01",
" 01.41.25 JOB00285 IEF403I LISTC - STARTED - TIME=01.41.25",
" 01.41.25 JOB00285 IEF404I LISTC - ENDED - TIME=01.41.25",
" 01.41.25 JOB00285 $HASP395 LISTC ENDED - RC=0004",
"0------ JES2 JOB STATISTICS ------",
"- 31 MAR 2024 JOB EXECUTION DATE",
"- 8 CARDS READ",
"- 67 SYSOUT PRINT RECORDS",
"- 0 SYSOUT PUNCH RECORDS",
"- 7 SYSOUT SPOOL KBYTES",
"- 0.00 MINUTES EXECUTION TIME"
],
"ddname": "JESMSGLG",
"id": "2",
"proctep": null,
"record_count": "16",
"stepname": "JES2"
},
{
"byte_count": "136",
"content": [
" 1 //LISTC JOB MSGCLASS=X,CLASS=A JOB00285",
" //*-----------------------------------------------------",
" //*"
],
"ddname": "JESJCL",
"id": "3",
"proctep": null,
"record_count": "3",
"stepname": "JES2"
},
{
"byte_count": "137",
"content": [
" ICH70001I IBMUSER LAST ACCESS AT 01:41:24 ON SUNDAY, MARCH 31, 2024",
" IEFA111I LISTC IS USING THE FOLLOWING JOB RELATED SETTINGS:",
" SWA=BELOW,TIOT SIZE=64K,DSENQSHR=DISALLOW,GDGBIAS=JOB",
" IEF236I ALLOC. FOR LISTC GO",
" IEF237I JES2 ALLOCATED TO SYSPRINT",
" IEF237I JES2 ALLOCATED TO SYSIN",
" IEF142I LISTC GO - STEP WAS EXECUTED - COND CODE 0004",
" IEF285I IBMUSER.LISTC.JOB00285.D0000102.? SYSOUT",
" IEF285I IBMUSER.LISTC.JOB00285.D0000101.? SYSIN",
" IEF373I STEP/GO /START 2024091.0141",
" IEF032I STEP/GO /STOP 2024091.0141",
" CPU: 0 HR 00 MIN 00.00 SEC SRB: 0 HR 00 MIN 00.00 SEC",
" VIRT: 80K SYS: 308K EXT: 16K SYS: 9816K",
" ATB- REAL: 228K SLOTS: 0K",
" VIRT- ALLOC: 13M SHRD: 0M",
" IEF375I JOB/LISTC /START 2024091.0141",
" IEF033I JOB/LISTC /STOP 2024091.0141",
" CPU: 0 HR 00 MIN 00.00 SEC SRB: 0 HR 00 MIN 00.00 SEC"
],
"ddname": "JESYSMSG",
"id": "4",
"proctep": null,
"record_count": "18",
"stepname": "JES2"
},
{
"byte_count": "125",
"content": [
"1IDCAMS SYSTEM SERVICES TIME: 01:41:25 03/31/24 PAGE 1",
"0 ",
" LISTCAT ENTRIES(CATALOG.TEST01)",
"0IDC3012I ENTRY CATALOG.TEST01 NOT FOUND",
" IDC3009I ** VSAM CATALOG RETURN CODE IS 8 - REASON CODE IS IGG0CLEG-42",
" IDC1566I ** CATALOG.TEST01 NOT LISTED",
"1IDCAMS SYSTEM SERVICES TIME: 01:41:25 03/31/24 PAGE 2",
"0 THE NUMBER OF ENTRIES PROCESSED WAS:",
"0 AIX -------------------0",
" ALIAS -----------------0",
" CLUSTER ---------------0",
" DATA ------------------0",
" GDG -------------------0",
" INDEX -----------------0",
" NONVSAM ---------------0",
" PAGESPACE -------------0",
" PATH ------------------0",
" SPACE -----------------0",
" USERCATALOG -----------0",
" TAPELIBRARY -----------0",
" TAPEVOLUME ------------0",
" TOTAL -----------------0",
"0 THE NUMBER OF PROTECTED ENTRIES SUPPRESSED WAS 0",
"0IDC0001I FUNCTION COMPLETED, HIGHEST CONDITION CODE WAS 4",
"0 ",
"0IDC0002I IDCAMS PROCESSING COMPLETE. MAXIMUM CONDITION CODE WAS 4"
],
"ddname": "SYSPRINT",
"id": "102",
"proctep": null,
"record_count": "26",
"stepname": "GO"
}
],
"duration": 1,
"job_class": "A",
"job_id": "JOB00285",
"job_name": "LISTC",
"owner": "IBMUSER",
"priority": "1",
"program_name": "IDCAMS",
"queue_position": "38",
"ret_code": {
"code": 4,
"msg": "CC",
"msg_code": "0004",
"msg_txt": "The job return code 4 was non-zero in the job output, this job has failed.",
"steps": [
{
"step_cc": 4,
"step_name": "GO"
}
]
},
"subsystem": "N1",
"svc_class": "?",
"system": "VS01"
}
],
"mode": "0600",
"owner": "BPXROOT",
"size": 477,
"src": "/u/ibmuser/.ansible/tmp/ansible-tmp-1711863652.3322203-29040-37539778899676/source",
"state": "file",
"uid": 0
}
MSG:
The JCL submitted with job id JOB00285 but there was an error, please review the error for further details: The job return code 4 was non-zero in the job output, this job has failed.
...ignoring
TASK [display results when rc > 4] ******************************************************************************************************************************************************************************
skipping: [ezdwazi04] => {
"false_condition": "jcl_result.jobs[0].ret_code.code > 4"
}
PLAY RECAP ******************************************************************************************************************************************************************************************************
ezdwazi04 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=1
JCLがRC=12で終了する例 (不当なEntryを指定)
実行例
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_jcl_listc_test01.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [submit a JCL] *********************************************************************************************************************************************************************************************
TASK [submit JCL] ***********************************************************************************************************************************************************************************************
fatal: [ezdwazi04]: FAILED! => {
"changed": false,
"dest": "/tmp/ansible.mwolmtkq",
"duration": 1,
"gid": 0,
"group": "SYS1",
"is_binary": false,
"jobs": [
{
"asid": "0",
"class": "A",
"content_type": "",
"creation_date": "2024-03-31",
"creation_time": "1:42:20",
"ddnames": [
{
"byte_count": "133",
"content": [
"1 J E S 2 J O B L O G -- S Y S T E M V S 0 1 -- N O D E N 1",
"0 ",
" 01.42.20 JOB00286 ---- SUNDAY, 31 MAR 2024 ----",
" 01.42.20 JOB00286 IRR010I USERID IBMUSER IS ASSIGNED TO THIS JOB.",
" 01.42.21 JOB00286 ICH70001I IBMUSER LAST ACCESS AT 01:42:20 ON SUNDAY, MARCH 31, 2024",
" 01.42.21 JOB00286 $HASP373 LISTC STARTED - INIT 6 - CLASS A - SYS VS01",
" 01.42.21 JOB00286 IEF403I LISTC - STARTED - TIME=01.42.21",
" 01.42.21 JOB00286 IEF404I LISTC - ENDED - TIME=01.42.21",
" 01.42.21 JOB00286 $HASP395 LISTC ENDED - RC=0012",
"0------ JES2 JOB STATISTICS ------",
"- 31 MAR 2024 JOB EXECUTION DATE",
"- 8 CARDS READ",
"- 48 SYSOUT PRINT RECORDS",
"- 0 SYSOUT PUNCH RECORDS",
"- 6 SYSOUT SPOOL KBYTES",
"- 0.00 MINUTES EXECUTION TIME"
],
"ddname": "JESMSGLG",
"id": "2",
"proctep": null,
"record_count": "16",
"stepname": "JES2"
},
{
"byte_count": "136",
"content": [
" 1 //LISTC JOB MSGCLASS=X,CLASS=A JOB00286",
" //*-----------------------------------------------------",
" //*"
],
"ddname": "JESJCL",
"id": "3",
"proctep": null,
"record_count": "3",
"stepname": "JES2"
},
{
"byte_count": "137",
"content": [
" ICH70001I IBMUSER LAST ACCESS AT 01:42:20 ON SUNDAY, MARCH 31, 2024",
" IEFA111I LISTC IS USING THE FOLLOWING JOB RELATED SETTINGS:",
" SWA=BELOW,TIOT SIZE=64K,DSENQSHR=DISALLOW,GDGBIAS=JOB",
" IEF236I ALLOC. FOR LISTC GO",
" IEF237I JES2 ALLOCATED TO SYSPRINT",
" IEF237I JES2 ALLOCATED TO SYSIN",
" IEF142I LISTC GO - STEP WAS EXECUTED - COND CODE 0012",
" IEF285I IBMUSER.LISTC.JOB00286.D0000102.? SYSOUT",
" IEF285I IBMUSER.LISTC.JOB00286.D0000101.? SYSIN",
" IEF373I STEP/GO /START 2024091.0142",
" IEF032I STEP/GO /STOP 2024091.0142",
" CPU: 0 HR 00 MIN 00.00 SEC SRB: 0 HR 00 MIN 00.00 SEC",
" VIRT: 76K SYS: 308K EXT: 16K SYS: 9800K",
" ATB- REAL: 228K SLOTS: 0K",
" VIRT- ALLOC: 13M SHRD: 0M",
" IEF375I JOB/LISTC /START 2024091.0142",
" IEF033I JOB/LISTC /STOP 2024091.0142",
" CPU: 0 HR 00 MIN 00.00 SEC SRB: 0 HR 00 MIN 00.00 SEC"
],
"ddname": "JESYSMSG",
"id": "4",
"proctep": null,
"record_count": "18",
"stepname": "JES2"
},
{
"byte_count": "125",
"content": [
"1IDCAMS SYSTEM SERVICES TIME: 01:42:21 03/31/24 PAGE 1",
"0 ",
" LISTCAT ENTRIES(TTTTTTTTTTTTTTT)",
"0IDC3203I ITEM 'TTTTTTTTTTTTTTT' DOES NOT ADHERE TO RESTRICTIONS",
"0IDC3202I ABOVE TEXT BYPASSED UNTIL NEXT COMMAND. CONDITION CODE IS 12",
"0 ",
"0IDC0002I IDCAMS PROCESSING COMPLETE. MAXIMUM CONDITION CODE WAS 12"
],
"ddname": "SYSPRINT",
"id": "102",
"proctep": null,
"record_count": "7",
"stepname": "GO"
}
],
"duration": 1,
"job_class": "A",
"job_id": "JOB00286",
"job_name": "LISTC",
"owner": "IBMUSER",
"priority": "1",
"program_name": "IDCAMS",
"queue_position": "39",
"ret_code": {
"code": 12,
"msg": "CC",
"msg_code": "0012",
"msg_txt": "The job return code 12 was non-zero in the job output, this job has failed.",
"steps": [
{
"step_cc": 12,
"step_name": "GO"
}
]
},
"subsystem": "N1",
"svc_class": "?",
"system": "VS01"
}
],
"mode": "0600",
"owner": "BPXROOT",
"size": 478,
"src": "/u/ibmuser/.ansible/tmp/ansible-tmp-1711863707.2490025-29245-262516146451725/source",
"state": "file",
"uid": 0
}
MSG:
The JCL submitted with job id JOB00286 but there was an error, please review the error for further details: The job return code 12 was non-zero in the job output, this job has failed.
...ignoring
TASK [display results when rc > 4] ******************************************************************************************************************************************************************************
ok: [ezdwazi04] => {}
MSG:
Result: JOB00286 / {'msg': 'CC', 'msg_code': '0012', 'code': 12, 'msg_txt': 'The job return code 12 was non-zero in the job output, this job has failed.', 'steps': [{'step_name': 'GO', 'step_cc': 12}]}
PLAY RECAP ******************************************************************************************************************************************************************************************************
ezdwazi04 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
JCLの場合一般的にRC=0, RC=4は許容される結果と言えますが、AnsibleのタスクとしてはRC=0以外はエラーと判断されてしまいます。
Playbook上の最後のタスクは、JCLのReturn Codeの数値を判定し4より大きい場合のみJCL結果の一部の情報を出力するようにします。そのため最初の2つのケース(RC=0, RC=4)では最後のメッセージ出力のタスクはスキップされ、最後のケース(RC=12)の場合のみ実行される結果となっています。
ログを見てみると、Jinja2により解釈されたテンプレートが一旦USS上のテンポラリーのディレクトリ(/u/ibmuser/.ansible/tmp/...:
: SSHSユーザーのホーム以下) に転送され、それがSubmitされるという処理が内部的に行われているものと思われます。
3.データセットのダンプ/リストア
zos_backup_restoreというモジュールを使います。
このモジュールは大きく2種類のオペレーションが行えます。1つはデータセットの「ダンプ」(backup)で、もう1つはダンプされたデータセットの「リストア」(restore)です。それぞれのオペレーションはパラメーターを切り替えることで使い分けます。
このモジュールでは内部的にADRDSSUによるダンプ/リストアが行われますが、それだけでなくAMATERSEによる圧縮/解凍も合わせて行ってくれます。従って、これを利用してある環境から取得したダンプ/圧縮した情報を別の環境にコピーして解凍/リストアすることができます。
ここでは、ある環境で適当なデータセットを選択して論理ダンプ/圧縮し、別の環境で解凍/リストアする、ということを試してみたいと思います。
論理ダンプ取得
Wazi aaSのStock Imageに含まれるCICS関連のデータセットのうちの一部を適当に抜粋して論理ダンプを取得してみます。
DSLIST - Data Sets Matching CICSTS61 Row 45 of 64
Command - Enter "/" to select action Message Volume
-------------------------------------------------------------------------------
CICSTS61.DFHCSD *VSAM*
CICSTS61.DFHCSD.DATA USRVS1
CICSTS61.DFHCSD.INDEX USRVS1
CICSTS61.SAMPLE.DFHAIPTH *PATH*
CICSTS61.SAMPLE.DFHCTAIX *AIX *
CICSTS61.SAMPLE.DFHCTAIX.DATA USRVS1
CICSTS61.SAMPLE.DFHCTAIX.INDEX USRVS1
CICSTS61.SAMPLE.DFHCTCUS *VSAM*
CICSTS61.SAMPLE.DFHCTCUS.DATA USRVS1
CICSTS61.SAMPLE.DFHCTCUS.INDEX USRVS1
CICSTS61.SAMPLE.DFHCTHLP *VSAM*
CICSTS61.SAMPLE.DFHCTHLP.DATA USRVS1
CICSTS61.SAMPLE.DFHCTHLP.INDEX USRVS1
CICSTS61.SYSIN USRVS1
CICSTS61.SYSIN.BK USRVS1
CICSTS61.SYSIN.BK.TEST USRVS1
CICSTS61.SYSIN2 USRVS1
上のあたりの論理ダンプを取得するPlaybookを作成してみます。
- name: get a logical dump and download
hosts: ezdwazi04
environment: "{{ environment_vars }}"
gather_facts: no
vars:
datasetIncludeList:
- CICSTS61.SYSIN*
- CICSTS61.SYSIN.**
- CICSTS61.*CSD
- CICSTS61.SAMPLE.*
tasks:
- name: backup test01
ibm.ibm_zos_core.zos_backup_restore:
operation: backup
data_sets:
include: "{{ datasetIncludeList }}"
backup_name: /tmp/my_backup.dzp
overwrite: true
- name: download test01
ibm.ibm_zos_core.zos_fetch:
src: /tmp/my_backup.dzp
dest: ./backup/my_backup.dzp
is_binary: true
flat: true
1つ目のタスクで zos_backup_restoreモジュールのoperation: backup
を指定することで、バックアップ取得(ダンプ取得)することを指示しています。data_setsのincludeで取得したいデータセットのリストを指定しています。ダンプ/圧縮した結果はUSS上の/tmp/my_backup.dzp
に出力するようにしています。
2つ目のタスクでは、zos_fetchというモジュールを使用して、上で取得した圧縮ファイルをローカル(Ansible Control Node)にコピーしています。
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_logical_dump.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [get a logical dump and download] **************************************************************************************************************************************************************************
TASK [backup test01] ********************************************************************************************************************************************************************************************
changed: [ezdwazi04] => {
"backup_name": "",
"changed": true,
"message": ""
}
TASK [download test01] ******************************************************************************************************************************************************************************************
changed: [ezdwazi04] => {
"changed": true,
"data_set_type": "USS",
"dest": "/home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/sample/backup/my_backup.dzp",
"file": "/tmp/my_backup.dzp",
"is_binary": true
}
PLAY RECAP ******************************************************************************************************************************************************************************************************
ezdwazi04 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
これで、論理ダンプ/圧縮したファイル my_backup.dzp
が取得されました。
論理ダンプのリストア
上で取得されたファイル my_backup.dzp
をリストアしてみます。
実際には別の環境にリストアすることを想定していますが、ここでは動作確認ということで、同じ環境の別のHLQにリストアしてみます。
リストア用のPlaybookを作成してみます。
- name: upload and restore
hosts: ezdwazi04
environment: "{{ environment_vars }}"
gather_facts: no
vars:
backupFile: my_backup.dzp
storageClass: SCBASE
targetHLQ: TTT
tasks:
- name: upload test01
ibm.ibm_zos_core.zos_copy:
src: ./sample/backup/{{ backupFile }}
dest: /tmp/{{ backupFile }}
is_binary: true
force: true
- name: restore test01
ibm.ibm_zos_core.zos_backup_restore:
operation: restore
backup_name: /tmp/{{ backupFile }}
overwrite: true
sms_storage_class: "{{ storageClass }}"
hlq: "{{ targetHLQ }}"
1つ目のタスクでは、zos_copyモジュールを使用して、先に取得したファイルをターゲット環境のUSS上にアップロードしています。
2つ目のタスクでは、zos_backup_restoreモジュールのoperation: restore
を指定することで、リストアすることを指示しています。hlq: xxx
でターゲットとなるHLQを指定しています。これを指定していない場合はAnsibleから接続時に使用したユーザー名がHLQとなります。
※ADRDSSUユーティリティーを使用したRESTOREではデータセット名を変更するなど細かな制御が行えますが、Ansible経由でのRESTOREでは利用できる操作は限定的のようです。
参考: Logical data set restore
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_restore.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [upload and restore] ***************************************************************************************************************************************************************************************
TASK [upload test01] ********************************************************************************************************************************************************************************************
ok: [ezdwazi04] => {
"changed": false,
"dest": "/tmp/my_backup.dzp",
"gid": 0,
"group": "SYS1",
"is_binary": true,
"mode": "0644",
"owner": "BPXROOT",
"size": 101376,
"src": "./sample/backup/my_backup.dzp",
"state": "file",
"uid": 0
}
TASK [restore test01] *******************************************************************************************************************************************************************************************
changed: [ezdwazi04] => {
"backup_name": "",
"changed": true,
"message": ""
}
PLAY RECAP ******************************************************************************************************************************************************************************************************
ezdwazi04 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
リストアされたデータセットを確認してみます。
DSLIST - Data Sets Matching TTT Row 1 of 16
Command - Enter "/" to select action Message Volume
-------------------------------------------------------------------------------
TTT.DFHCSD *VSAM*
TTT.DFHCSD.DATA USRVS1
TTT.DFHCSD.INDEX USRVS1
TTT.SAMPLE.DFHCTAIX *VSAM*
TTT.SAMPLE.DFHCTAIX.DATA USRVS1
TTT.SAMPLE.DFHCTAIX.INDEX USRVS1
TTT.SAMPLE.DFHCTCUS *VSAM*
TTT.SAMPLE.DFHCTCUS.DATA USRVS1
TTT.SAMPLE.DFHCTCUS.INDEX USRVS1
TTT.SAMPLE.DFHCTHLP *VSAM*
TTT.SAMPLE.DFHCTHLP.DATA USRVS1
TTT.SAMPLE.DFHCTHLP.INDEX USRVS1
TTT.SYSIN USRVS1
TTT.SYSIN.BK USRVS1
TTT.SYSIN.BK.TEST USRVS1
TTT.SYSIN2 USRVS1
***************************** End of Data Set list ****************************
論理ダンプされたデータセットがリストアされたことが確認できました。
※必要に応じてUser CatalogやAliasの作成は別途検討してください。
※ここではzos_backup_restoreモジュールで取得したbackupファイルをリストアしていますが、これは内部的にはADRDSSU、AMATERSEが使われていますので、これらのユーティリティーで取得されたbackupファイルであれば、zos_backup_restoreモジュールでリストアすることができます。
4.IPLPARM変更
IPL時に参照されるパラメータの一部を変更するということをやってみます。ここでは、Wazi aaSのStockImage環境を想定し、この環境のIEASYMxxで指定されている環境変数の設定を変更する、ということをやってみます。
IPL関連のパラメータを変更する場合、ヘタに変更するとIPLできなくなるリスクがありますので、既存の設定でもIPLできるよう保険をかけておくような形を意識してPlaybook作成するようにします。
変更前IPL関連情報
D IPLINFO
IEE254I 03.19.05 IPLINFO DISPLAY 867
SYSTEM IPLED AT 03.14.42 ON 04/02/2024
RELEASE z/OS 02.05.00 LICENSE = z/OS
USED LOADK2 IN SYS0.IPLPARM ON 0DE28
ARCHLVL = 2 MTLSHARE = N
VALIDATED BOOT: NO
IEASYM LIST = (00,K2)
IEASYS LIST = (00) (OP)
IODF DEVICE: ORIGINAL(0DE28) CURRENT(0DE28)
IPL DEVICE: ORIGINAL(0DE27) CURRENT(0DE27) VOLUME(D25VS1)
VM CPID = zHYPaaS
VM UUID = 0E72B0AB-495B-4B84-90FE-0DE4A82DF91E
VM NAME = k8s_ead8
VM EXT NAME = k8s_ead8711ba2cc4d08a16fd37427f4f01a_02g7_0e72b0ab-495b
-4b84-90fe-0de4a82df91e
SYSDEF
SYMDEF(&JESNAME='VSIPLEX')
SYMDEF(&OWNNODE='00')
SYMDEF(&VTAMCFG='00')
SYMDEF(&VTAMSA='00')
SYSPARM(00)
SYMDEF(&IZUPRM='00')
SYMDEF(&COMMAND='00')
SYMDEF(&CONSOLE='00')
SYMDEF(&COUPLE='00')
SYMDEF(&IDFPRM='00')
SYMDEF(&IOEPRM='00')
SYMDEF(&LPALST='00')
SYMDEF(&OMVSPARM='00')
SYMDEF(&OPT='00')
SYMDEF(&PROGNME='00')
SYMDEF(&SCHED='00')
SYSDEF SYSNAME(VS01)
SYMDEF(&J2SPVL='JSPVS')
SYMDEF(&J2CKVL1='JCKVS1')
SYMDEF(&J2CKHLQ='VS01')
SYMDEF(&IPADDR4A='10')
SYMDEF(&IPADDR4B='1')
SYMDEF(&IPADDR4C='1')
SYMDEF(&IPADDR4D='2')
SYMDEF(&IPROUT4A='10')
SYMDEF(&IPROUT4B='1')
SYMDEF(&IPROUT4C='1')
SYMDEF(&IPROUT4D='0')
SYMDEF(&IPDRUT4A='10')
SYMDEF(&IPDRUT4B='1')
SYMDEF(&IPDRUT4C='1')
SYMDEF(&IPDRUT4D='1')
SYMDEF(&NODE='63')
SYMDEF(&SSCPID='5065')
SYMDEF(&HOSTSA='4')
SYMDEF(&NAMSVRA='10')
SYMDEF(&NAMSVRB='1')
SYMDEF(&NAMSVRC='1')
SYMDEF(&NAMSVRD='1')
SYMDEF(&J2CKVL2='')
SYMDEF(&TCPHOSTNAME_='STD1')
SYMDEF(&TCPDOMAIN_='IBM.COM')
SYMDEF(&VPCVSIIPADDRESS.='10.1.1.2')
SYMDEF(&CERTEXPIRE='2025-11-01')
SYMDEF(&CNMDOMN='CNM01')
SYMDEF(&CNMNETID='NETA')
SYMDEF(&CNMTCPN='TCPIP')
/* Begin Ansible Block Insert */
SYMDEF(&CNMDOMN='CNM01')
SYMDEF(&CNMTCPN='TCPIP')
SYMDEF(&CNMNETID='EXPNET')
SYMDEF(&JES2STR_='(COLD,NOREQ)')
SYMDEF(&DBGMGR='IPL')
SYMDEF(&EQAPROF='IPL')
SYMDEF(&EQARMTD='IPL')
SYMDEF(&CICSTS61='IPL')
SYMDEF(&CSQ9MSTR='IPL')
SYMDEF(&CSQ9CHIN='IPL')
SYMDEF(&IMS15RL1='IPL')
SYMDEF(&IMS15CR1='IPL')
SYMDEF(&DBC1MSTR='IPL')
SYMDEF(&DBD1MSTR='IPL')
SYMDEF(&IZUANG1='IPL')
SYMDEF(&IZUSVR1='IPL')
SYMDEF(&JMON='IPL')
SYMDEF(&RSED='IPL')
SYMDEF(&RSEAPI='IPL')
SYMDEF(&DBB='IPL')
SYMDEF(&DBBS='IPL')
SYMDEF(&ZOSCSRV='IPL')
SYMDEF(&RESOLV_='RESSETUP')
/* End Ansible Block Insert */
Wazi aaSのStockImageでは、各種サブシステムがある程度セットアップされた状態のz/OS環境が提供されています。各サブシステムはNetviewのスクリプトで起動/停止などが管理されていますが、IPL時に起動するかどうかはIEASYMxxに指定されているシンボルにより制御されます。
参考: Wazi aaS: クラウド上でのメインフレーム開発環境構築 - (5) Stock Iamge確認 - Netview関連
例えば SYMDEF(&CICSTS61='IPL')
と指定することでIPL時に自動でCICSリージョンが起動するようになっています。「IPL」部分を「NOS」に変更するとIPL時に自動起動されなくなります。
ここでは、一部のサブシステムの自動起動用のシンボルを変更して不要なものはIPL時に自動起動させないようにする、というカスタマイズをAnsible Playbookで実装してみたいと思います。
このメンバーを直接編集してもよいですが、万が一この変更によりIPLがうまくいかなくなってしまった時のために、現行設定でもIPLできる手段を残すようにします。そのため、LOADxxも確認しておきます。
IODF 00 PROV DEFAULT 00
INITSQA 0001M
SYSCAT OPEVS1143CCATALOG.VS01.MASTER
IEASYM (00,K2)
SYSPLEX LOCAL
PARMLIB K2.PARMLIB USRVS1
PARMLIB SYS1.PARMLIB
PARMLIB SYS1.PARMLIB.INSTALL
変更方針
以下のようにカスタマイズするようにしたいと思います。
- 新規にカスタマイズ用のPARMLIBライブラリーを作成
- 変更対象のメンバー(IEASYM00)をカスタマイズ用ライブラリーにコピー
- LOADK2のバックアップを取得し、LOADK2にカスタマイズ用ライブラリーを上位コンカチ
- カスタマイズ用ライブラリー上のIEASYM00を変更
※Wazi aaSの場合デフォルトで使われるLOAD PARMは決まってしまっているので、基本的にはLOADK2が使用されます。ただ、明示的にLOAD PARM指定でIPLすることもできるので、LOADK2のバックアップを取得しておけば、最悪デフォルトのLOADK2でIPLできなくなった場合でもバックアップ取得したLOADxxでIPLすれば元の環境で起動できるはず。
参考: Wazi as a Service - Operating with the serial console
Playbook作成
さて、上のような方針でPlaybook作成してみます。
- name: modify parmlib
hosts: ezdwazi04
environment: "{{ environment_vars }}"
gather_facts: no
vars:
oldParmlib: SYS1.PARMLIB
newParmlib: SYS1.PARMLIB.TEST01
storageClass: SCBASE
LOADParmMember: SYS0.IPLPARM(LOADK2)
LOADParmMemberBK: SYS0.IPLPARM(LOADK9)
oldIEASYMMember: "{{ oldParmlib }}(IEASYM00)"
newIEASYMMember: "{{ newParmlib }}(IEASYM00)"
componentList:
- "&CICSTS61"
- "&CSQ9MSTR"
- "&CSQ9CHIN"
- "&ZOSCSRV"
IPLOption: "NOS"
tasks:
- name: Create new Parmlib dataset
ibm.ibm_zos_core.zos_data_set:
name: "{{ newParmlib }}"
type: PDS
space_type: TRK
space_primary: 45
space_secondary: 15
sms_storage_class: "{{ storageClass }}"
- name: copy parmlib dataset
ibm.ibm_zos_core.zos_copy:
src: "{{ oldIEASYMMember }}"
dest: "{{ newIEASYMMember }}"
remote_src: true
force: true
- name: add PARMLIB library to LOADxx
ibm.ibm_zos_core.zos_blockinfile:
src: "{{ LOADParmMember }}"
insertbefore: "^.*PARMLIB {{ oldParmlib }}[^.]"
block: |
PARMLIB {{ newParmlib }}
marker: "* {mark} ANSIBLE MANAGED BLOCK"
backup: true
backup_name: "{{ LOADParmMemberBK }}"
- name: replace IPL option
ibm.ibm_zos_core.zos_lineinfile:
src: "{{ newIEASYMMember }}"
backrefs: true
regexp: "^SYMDEF[(]{{ item }}="
line: "SYMDEF({{ item }}='{{ IPLOption }}')"
force: true
loop: "{{ componentList }}"
【Task1: 新規PARMLIBライブラリー作成】
zos_data_setモジュールを使用し、新たなPARMLIBライブラリー(ここではSYS1.PARMLIB.TES01)を作成します。PARMLIBのライブラリはPDSEだと読み込めないのでPDSにする必要がありますのでご注意ください。
【Task2: 変更対象メンバーのコピー】
zos_copyモジュールを使用し、新しく作成したPARMLIBライブラリー(SYS1.PARMLIB.TEST01)に変更対象のメンバー(IEASYM00)をコピーします。
【Task3: LOADxx変更】
zos_blockinfileモジュールを使用して、SYS0.IPLPARM(LOADK2)にTask1で作成したライブラリーを上位コンカチします。
ここで使用しているzos_blockinfileモジュールを用いることで、複数行の文字列をPDSメンバーやUSSファイルに挿入することができます。今回は1行分しか挿入していないので後述のzos_lineinfileモジュール(1行単位の文字列を扱うためのモジュール)を使うこともできますが、動作確認の意味もあるためあえて別のモジュールを使用しています。
文字列を挿入する位置は、insertbefore
パラメーターで制御しています。ここで指定した正規表現にマッチする行の直前に文字列が挿入されることになります。ここでは、SYS1.PARMLIBの指定行の直前に挿入されるよう指定しています(上位コンカチ)。
挿入した文字列の前後の行には、marker
で指定した文字列が挿入されることになります。デフォルトだと以下のような文字列でくくられた行が挿入されることになります。(この前後のマーカー挿入は抑止できなさそうです。)
# BEGIN ANSIBLE MANAGED BLOCK
...
# END ANSIBLE MANAGED BLOCK
参考: Syntax rules for LOADxx
上のマニュアルに記載があるように、LOADxxのコメントは先頭に「*
」を指定することになりますので、marker
オプションで「*
」を先頭に付与した文字列を指定しておきます。
また、この時変更対象のメンバーのオリジナルのバックアップを取得するために、backup: true
を指定しbackup_name
にバックアップ用のメンバー名を指定しています。こうすることで、最悪元のLOADxxを使用してIPLできる状態を残しています。
【Task4: IEASYMxx変更】
zos_lineinfileモジュールを使用して、Task2でコピーしたIEASYM00(LOADxxで上位コンカチされたライブラリーのメンバー)を変更していきます。
このモジュールでは、特定の条件にマッチする行を指定の文字列に置き換えることができます。条件指定には正規表現が利用できます。具体的にはregexp
で指定した条件に合致する行がline
で指定した文字列に置き換えられます。
上の例では、「SYMDEF(xxx=
」という文字列に合致するものを置き換えるようにしており、xxx
部分は変数で与えるようにしています。また、複数のシンボルを同じルールで変更することを想定しているので、Playbookの基本機能であるloop機能を使ってリスト化された変数それぞれに対して置換を実行するようにしています(loopに指定した変数のリストの各項目は {{ item }}
変数で参照できます)。
こうすることで変数リスト(上の例だとcomponentList)に指定したシンボルの定義部分を置換することになります。上のPlaybookでは、CICS、MQ、z/OS Connect関連のアドレススペースはIPL時に起動しないよう'NOS'にシンボルの値を変更するようにしています。
Playbook実行
上のPlaybook実行してみます。
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_parmlib_test01.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [modify parmlib] *********************************************************************************************************************************************************
TASK [Create new Parmlib dataset] *********************************************************************************************************************************************
changed: [ezdwazi04] => {
"changed": true,
"message": "",
"names": [
"SYS1.PARMLIB.TEST01"
]
}
TASK [copy parmlib dataset] ***************************************************************************************************************************************************
changed: [ezdwazi04] => {
"changed": true,
"dest": "SYS1.PARMLIB.TEST01(IEASYM00)",
"is_binary": false,
"src": "SYS1.PARMLIB(IEASYM00)"
}
TASK [add PARMLIB library to LOADxx] ******************************************************************************************************************************************
changed: [ezdwazi04] => {
"backup_name": "SYS0.IPLPARM(LOADK9)",
"changed": 1,
"cmd": "dmod -b -c IBM-1047 -m BEGIN\nEND\n* {mark} ANSIBLE MANAGED BLOCK -j -s -e /^.*PARMLIB SYS1.PARMLIB[^.]/i\\PARMLIB SYS1.PARMLIB.TEST01/$ -e $ a\\PARMLIB SYS1.PARMLIB.TEST01 SYS0.IPLPARM(LOADK2) ",
"found": 1
}
TASK [replace IPL option] *****************************************************************************************************************************************************
changed: [ezdwazi04] => (item=&CICSTS61) => {
"ansible_loop_var": "item",
"changed": 1,
"cmd": "dsedhelper -d -f -c IBM-1047 -r /^SYMDEF[(]&CICSTS61=/c\\SYMDEF(&CICSTS61='NOS')/$ SYS1.PARMLIB.TEST01(IEASYM00) ",
"found": 1,
"item": "&CICSTS61"
}
changed: [ezdwazi04] => (item=&CSQ9MSTR) => {
"ansible_loop_var": "item",
"changed": 1,
"cmd": "dsedhelper -d -f -c IBM-1047 -r /^SYMDEF[(]&CSQ9MSTR=/c\\SYMDEF(&CSQ9MSTR='NOS')/$ SYS1.PARMLIB.TEST01(IEASYM00) ",
"found": 1,
"item": "&CSQ9MSTR"
}
changed: [ezdwazi04] => (item=&CSQ9CHIN) => {
"ansible_loop_var": "item",
"changed": 1,
"cmd": "dsedhelper -d -f -c IBM-1047 -r /^SYMDEF[(]&CSQ9CHIN=/c\\SYMDEF(&CSQ9CHIN='NOS')/$ SYS1.PARMLIB.TEST01(IEASYM00) ",
"found": 1,
"item": "&CSQ9CHIN"
}
changed: [ezdwazi04] => (item=&ZOSCSRV) => {
"ansible_loop_var": "item",
"changed": 1,
"cmd": "dsedhelper -d -f -c IBM-1047 -r /^SYMDEF[(]&ZOSCSRV=/c\\SYMDEF(&ZOSCSRV='NOS')/$ SYS1.PARMLIB.TEST01(IEASYM00) ",
"found": 1,
"item": "&ZOSCSRV"
}
PLAY RECAP ********************************************************************************************************************************************************************
ezdwazi04 : ok=4 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
【結果確認】
SYS1.PARMLIB.TEST01という新しいデータセットが作成されています。
SYS1.PARMLIB.TEST01(IEASYM00) の中身を確認すると、Playbookで指定したシンボルの値が'NOS'に変更されていることが確認できます。
SYS0.IPLPARM(LOADK2)を確認すると、SYS.PARMLIBの上位にSYS1.PARMLIB.TEST01がコンカチされていることが確認できます。
SYS0.IPLPARM(LOADK9)を確認すると、元のLOADxx(LOADK2)のバックアップが取得されていることが確認できます。
変更が問題なさそうなのでIPLして動作確認 => IPL後指定したサブシステムが起動していないことが確認できました。
5.zFSマウント制御
zos_mount というモジュールを使うと、zFSのマウント/アンマウントの制御が行えます。
※このモジュールではマウント/アンマウント処理を行うだけでなく、このマウント設定をIPLをまたがっても永続的にシステムに反映するためにBPXPRMxxにマウントコマンドを仕込む操作も含めて実施する機能が提供されているようです(persistentオプション)。しかしこれを指定するとうまく動かなかったので、ここではその部分は別のモジュールを使用して実装してみます。その方が細かい制御がしやすいかも。
zFSのデータセット、マウントポイントのUSS上のディレクトリは作成済みの想定です。
zFSマウント
zFSをマウントし、BPXPRMxxにマウント用の設定を追加するPlaybookを作成してみます。
- name: mount zfs
hosts: ezdwazi04
environment: "{{ environment_vars }}"
vars:
zfs_dataset: "TEST01.SAMPLE.ZFS"
zfs_mountpoint: "/tmp/test01"
bpxprm_member: "SYS1.PARMLIB(BPXPRM01)"
bpxprm_backup_member: "SYS1.PARMLIB(BPXPRM09)"
tasks:
- name: mount zfs
ibm.ibm_zos_core.zos_mount:
src: "{{ zfs_dataset }}"
path: "{{ zfs_mountpoint }}"
fs_type: ZFS
mount_opts: RW
state: mounted
register: tmp_result
- name: add mount command to BPXPRMxx
ibm.ibm_zos_core.zos_blockinfile:
src: "{{ bpxprm_member }}"
state: present
marker: "/* {mark} ANSIBLE MANAGED BLOCK for {{ zfs_dataset }} */"
block: |
MOUNT FILESYSTEM('{{ zfs_dataset }}')
MOUNTPOINT('{{ zfs_mountpoint }}')
TYPE(ZFS) MODE(RDWR)
backup: true
backup_name: "{{ bpxprm_backup_member }}"
when: tmp_result.changed
【Task1: マウント】
zFSのデータセットとマウントポイントを指定し、state
オプションにmounted
を指定することでマウント処理を行うことになります。マウント時のオプションとしてmount_opts
にRW
(Read/Write)を指定しています。
【Task2: BPXPRMxxへの定義追加】
Task1でマウント処理が行われた場合(changedのステータスになった場合)、BPXPRMxxにMOUNT用のコマンド追記するためのタスクが実行されるように when
オプションを指定しています。
BPXPRMxxへの追記は、zos_blockinfileモジュールを使用しています。
上のPlaybookを実行してみます。
※BPXPRMxxが含まれるデータセットをTSOなどで掴んでいるとBPXPRMxxの変更のタスクがエラーとなりますのでご注意ください。
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_mount_zfs.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [mount zfs] *******************************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************************
ok: [ezdwazi04]
TASK [mount zfs] *******************************************************************************************************************************************************************
changed: [ezdwazi04] => {
"allow_uid": true,
"automove": "AUTOMOVE",
"automove_list": "",
"changed": true,
"cmd": "tsocmd MOUNT FILESYSTEM\\( \\'TEST01.SAMPLE.ZFS\\' \\) MOUNTPOINT\\( \\'/tmp/test01\\' \\) TYPE\\( 'ZFS' \\) MODE\\(RDWR\\) SETUID WAIT SECURITY AUTOMOVE",
"fs_type": "ZFS",
"gid": 0,
"group": "SYS1",
"mode": "0755",
"mount_opts": "RW",
"owner": "BPXROOT",
"path": "/tmp/test01",
"persistent": null,
"rc": 0,
"size": 0,
"src": "TEST01.SAMPLE.ZFS",
"src_params": "",
"state": "directory",
"sysname": "",
"tag_ccsid": null,
"tag_untagged": null,
"uid": 0,
"unmount_opts": "NORMAL"
}
STDOUT:
MOUNT FILESYSTEM( 'TEST01.SAMPLE.ZFS' ) MOUNTPOINT( '/tmp/test01' ) TYPE( ZFS ) MODE(RDWR) SETUID WAIT SECURITY AUTOMOVE
TASK [add mount command to BPXPRMxx] ***********************************************************************************************************************************************
changed: [ezdwazi04] => {
"backup_name": "SYS1.PARMLIB(BPXPRM09)",
"changed": 1,
"cmd": "dmod -b -c IBM-1047 -m BEGIN\nEND\n/* {mark} ANSIBLE MANAGED BLOCK for TEST01.SAMPLE.ZFS */ -j $ a\\MOUNT FILESYSTEM('TEST01.SAMPLE.ZFS') \n MOUNTPOINT('/tmp/test01') \n TYPE(ZFS) MODE(RDWR) SYS1.PARMLIB(BPXPRM01) ",
"found": 0
}
PLAY RECAP *************************************************************************************************************************************************************************
ezdwazi04 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
【確認】
SDSFのFSにてZFSがマウントされていることを確認
SDSF FILE SYSTEMS VS01 VS01 LINE 1-20 (41)
COMMAND INPUT ===> SCROLL ===> CSR
NP DEVICE Path Type Mode Owner Name Status
12 /dsfs DSFS RDWR VS01 OMVS.VS01.UTILITY.DSFS ACTIVE
32 /u AUTOMNT RDWR VS01 *AMD/u ACTIVE
48 /tmp/test01 ZFS RDWR VS01 TEST01.SAMPLE.ZFS ACTIVE
..
BPXPRMxx確認
...
/* BEGIN ANSIBLE MANAGED BLOCK for TEST01.SAMPLE.ZFS */
MOUNT FILESYSTEM('TEST01.SAMPLE.ZFS')
MOUNTPOINT('/tmp/test01')
TYPE(ZFS) MODE(RDWR)
/* END ANSIBLE MANAGED BLOCK for TEST01.SAMPLE.ZFS */
末尾に上の設定が追記されていることが確認できました。
zFSアンマウント
同様にアンマウント用のPlaybookを作成してみます。
- name: unmount zfs
hosts: ezdwazi04
environment: "{{ environment_vars }}"
vars:
zfs_dataset: "TEST01.SAMPLE.ZFS"
zfs_mountpoint: "/tmp/test01"
bpxprm_member: "SYS1.PARMLIB(BPXPRM01)"
bpxprm_backup_member: "SYS1.PARMLIB(BPXPRM09)"
tasks:
- name: unmount zfs
ibm.ibm_zos_core.zos_mount:
src: "{{ zfs_dataset }}"
path: "{{ zfs_mountpoint }}"
fs_type: ZFS
mount_opts: RW
state: unmounted
register: tmp_result
- name: delete mount command from BPXPRMxx
ibm.ibm_zos_core.zos_blockinfile:
src: "{{ bpxprm_member }}"
state: absent
marker: "/* {mark} ANSIBLE MANAGED BLOCK for {{ zfs_dataset }} */"
backup: true
backup_name: "{{ bpxprm_backup_member }}"
when: tmp_result.changed
【Task1: アンマウント】
マウント用のタスクとほぼ同様ですが、state
パラメーターにunmounted
を指定しています。これにより指定したzFSがアンマウントされます。
【Task2: BPXPRMxxから定義削除】
これもマウント時のBPXPRMxxへの追加のTASKとほぼ同様ですが、state
パラメーターにabsent
を指定しています。これにより、先に作成したBlockが削除されます。
when
パラメーターでアンマウント処理が行われた場合にのrみ当タスクが実行されるよう指定しています。
上のPlaybookを実行してみます。
※BPXPRMxxが含まれるデータセットをTSOなどで掴んでいるとBPXPRMxxの変更のタスクがエラーとなりますのでご注意ください。
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_unmount_zfs.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [unmount zfs] *****************************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************************
ok: [ezdwazi04]
TASK [unmount zfs] *****************************************************************************************************************************************************************
changed: [ezdwazi04] => {
"allow_uid": true,
"automove": "AUTOMOVE",
"automove_list": "",
"changed": true,
"cmd": "",
"fs_type": "ZFS",
"gid": 0,
"group": "SYS1",
"mode": "0755",
"mount_opts": "RW",
"owner": "BPXROOT",
"path": "/tmp/test01",
"persistent": null,
"rc": 0,
"size": 4096,
"src": "TEST01.SAMPLE.ZFS",
"src_params": "",
"state": "directory",
"sysname": "",
"tag_ccsid": null,
"tag_untagged": null,
"uid": 0,
"unmount_opts": "NORMAL"
}
STDOUT:
UNMOUNT FILESYSTEM( TEST01.SAMPLE.ZFS )
TASK [delete mount command from BPXPRMxx] ******************************************************************************************************************************************
changed: [ezdwazi04] => {
"backup_name": "SYS1.PARMLIB(BPXPRM09)",
"changed": 1,
"cmd": "dmod -b -c IBM-1047 -m BEGIN\nEND\n/* {mark} ANSIBLE MANAGED BLOCK for TEST01.SAMPLE.ZFS */ -j //d SYS1.PARMLIB(BPXPRM01) ",
"found": 1
}
PLAY RECAP *************************************************************************************************************************************************************************
ezdwazi04 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
アンマウント処理が行われ、BPXPRMxxからも先に追加されたMOUNTの定義が削除されます。
6.USS操作
USSファイルのダウンロード/アップロード
ローカル - USS間での単純なファイルのダウンロード/アップロードは、それぞれ zos_fetchモジュール/zos_copyモジュールを使用して実装できます。
これらは、上の「データセットのダンプ/リストア」の例の中で示していますのでそちらをご参照ください。
ディレクトリ単位のアップロード
zos_copyモジュールローカル(Ansible Control Node)にあるディレクトリ配下のファイルを、USS上の特定のディレクトリにアップロードすることができます。元となるディレクトリにサブディレクトリが含まれる場合そのサブディレクトリの構造も含めてUSS上に転送されます。各ファイルは一括で文字コード変換されるか、もしくはバイナリーモードで転送されます。従って対象のディレクトリに含まれるファイルは全て同じencodingが使用されているテキスト・ファイルであるか、もしくは、全てバイナリー(文字コード変換無し)である必要があります。
ローカルに、以下のようなサンプルとして構造のディレクトリを用意します。
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ls -laR sample/files/TEST01
sample/files/TEST01:
total 16
drwxr-xr-x 4 user01 user01 4096 Apr 28 12:59 .
drwxr-xr-x 3 user01 user01 4096 Apr 28 13:01 ..
drwxr-xr-x 2 user01 user01 4096 Apr 28 12:59 subdir01
drwxr-xr-x 2 user01 user01 4096 Apr 28 13:00 subdir02
sample/files/TEST01/subdir01:
total 16
drwxr-xr-x 2 user01 user01 4096 Apr 28 12:59 .
drwxr-xr-x 4 user01 user01 4096 Apr 28 12:59 ..
-rw-r--r-- 1 user01 user01 4 Apr 28 12:59 file01_01.txt
-rw-r--r-- 1 user01 user01 4 Apr 28 12:59 file01_02.txt
sample/files/TEST01/subdir02:
total 16
drwxr-xr-x 2 user01 user01 4096 Apr 28 13:00 .
drwxr-xr-x 4 user01 user01 4096 Apr 28 12:59 ..
-rw-r--r-- 1 user01 user01 4 Apr 28 12:59 file02_01.txt
-rw-r--r-- 1 user01 user01 4 Apr 28 13:00 file02_02.txt
このディレクトリ/ファイル構造をUSS上にcopyするPlaybookを作成してみます。
- name: upload dir to USS
hosts: ezdwazi04
environment: "{{ environment_vars }}"
vars:
local_directory: "{{ playbook_dir }}/files/TEST01"
target_directory: "/u/TEST"
gather_facts: no
tasks:
- name: upload dir
ibm.ibm_zos_core.zos_copy:
src: "{{ local_directory }}"
dest: "{{ target_directory }}"
force: true
上のPlaybookを実行してみます。
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_upload_dir.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [upload dir to USS] ***********************************************************************************************************************************************************
TASK [upload dir] ******************************************************************************************************************************************************************
changed: [ezdwazi04] => {
"changed": true,
"dest": "/u/TEST/TEST01",
"gid": 0,
"group": "SYS1",
"is_binary": false,
"mode": "0755",
"owner": "BPXROOT",
"size": 8192,
"src": "/home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/sample/files/TEST01",
"state": "directory",
"uid": 0
}
PLAY RECAP *************************************************************************************************************************************************************************
ezdwazi04 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
USS上のディレクトリを確認してみます。
IBMUSER : /u/TEST : > ls -laRT TEST01
TEST01:
total 64
drwxr-xr-x 4 BPXROOT SYS1 8192 Apr 28 00:17 .
drwxr-xr-x 4 BPXROOT SYS1 8192 Apr 28 00:17 ..
drwxr-xr-x 2 BPXROOT SYS1 8192 Apr 28 00:17 subdir01
drwxr-xr-x 2 BPXROOT SYS1 8192 Apr 28 00:17 subdir02
TEST01/subdir01:
total 36
drwxr-xr-x 2 BPXROOT SYS1 8192 Apr 28 00:17 .
drwxr-xr-x 4 BPXROOT SYS1 8192 Apr 28 00:17 ..
t IBM-1047 T=on -rw-r--r-- 1 BPXROOT SYS1 4 Apr 28 00:17 file01_01.txt
t IBM-1047 T=on -rw-r--r-- 1 BPXROOT SYS1 4 Apr 28 00:17 file01_02.txt
TEST01/subdir02:
total 36
drwxr-xr-x 2 BPXROOT SYS1 8192 Apr 28 00:17 .
drwxr-xr-x 4 BPXROOT SYS1 8192 Apr 28 00:17 ..
t IBM-1047 T=on -rw-r--r-- 1 BPXROOT SYS1 4 Apr 28 00:17 file02_01.txt
t IBM-1047 T=on -rw-r--r-- 1 BPXROOT SYS1 4 Apr 28 00:17 file02_02.txt
ディレクトリ構造を含み、各ファイルが転送されていることがわかります。各ファイルはデフォルトではIBM-1047の文字コードに変換されています。
ちなみに、この後USS上のsubdir01配下のファイルを以下のように変更してみました。
- file01_01.txtを削除
- file01_02.txtの中身を更新
- file01_03.txtという新規ファイルを作成
その後、再度上のPlaybookを実行してみました。その結果、file01_01.txt, file01_02.txtはローカルの情報に上書きされましたが、新規で作成されたfile01_03.txtはそのまま残った状態となっていました。
※zos_copyモジュールでは、上のようにディレクトリ構造をまるごとアップロードすることができましたが、zos_fetchモジュールではUSSディレクトリ配下をまごとダウンロードするという操作はできないようです。
USSディレクトリの圧縮/解凍
USSディレクトリやファイルを圧縮/解凍する際は、それぞれzos_archiveモジュール/zos_unarchiveモジュールが利用できます。
(※これらのモジュールはUSS上のディレクトリ/ファイル以外にMVSデータセットの圧縮/解凍にも利用できます)
ここでは、ある環境で適当なUSSディレクトリをtarで固めて取得し、別の環境で解凍する、という操作を試してみたいと思います。
tarファイルへの圧縮、ローカルへの保管
あるディレクトリをtarで固めてローカル(Ansible Control Node)に取得するPlaybookを作成してみます。
- name: archive USS directory
hosts: ezdwazi04
environment: "{{ environment_vars }}"
vars:
source_directory: "/u/ibmuser/.ssh"
tmp_USS_directory: "/tmp"
backup_file: "ibmuser_ssh.tar"
local_directory: "{{ playbook_dir }}/backup"
gather_facts: no
tasks:
- name: archive
ibm.ibm_zos_core.zos_archive:
src: "{{ source_directory }}"
dest: "{{ tmp_USS_directory }}/{{ backup_file }}"
format:
name: tar
force: true
- name: download
ibm.ibm_zos_core.zos_fetch:
src: "{{ tmp_USS_directory }}/{{ backup_file }}"
dest: "{{ local_directory }}/{{ backup_file }}"
is_binary: true
flat: true
上のPlaybookを実行してみます。
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_archive.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [archive USS directory] *******************************************************************************************************************************************************
TASK [archive] *********************************************************************************************************************************************************************
changed: [ezdwazi04] => {
"archived": [
"/u/TEST/TEST01/subdir01",
"/u/TEST/TEST01/subdir02",
"/u/TEST/TEST01/subdir01/file01_02.txt",
"/u/TEST/TEST01/subdir01/file01_01.txt",
"/u/TEST/TEST01/subdir02/file02_01.txt",
"/u/TEST/TEST01/subdir02/file02_02.txt"
],
"arcroot": "/u/TEST",
"changed": true,
"dest": "/tmp/TEST01.tar",
"dest_state": "archive",
"expanded_exclude_sources": [],
"expanded_sources": [
"/u/TEST/TEST01"
],
"gid": 0,
"group": "SYS1",
"missing": [],
"mode": "0644",
"owner": "BPXROOT",
"size": 20480,
"state": "file",
"uid": 0,
"xmit_log_data_set": ""
}
TASK [download] ********************************************************************************************************************************************************************
changed: [ezdwazi04] => {
"changed": true,
"data_set_type": "USS",
"dest": "/home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/sample/backup/TEST01.tar",
"file": "/tmp/TEST01.tar",
"is_binary": true
}
PLAY RECAP *************************************************************************************************************************************************************************
ezdwazi04 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
指定したディレクトリが/tmp/TEST01.tarに固められ、それがローカルの.../backup/TEST01.tarファイルにダウンロードされました。
tarファイルの転送、解凍
上で取得されたtarファイルを、USS上の特定のディレクトリに解凍するPlaybookを作成してみます。
- name: unarchive USS directory
hosts: ezdwazi04
environment: "{{ environment_vars }}"
vars:
local_directory: "{{ playbook_dir }}/backup"
backup_file: "TEST01.tar"
target_directory: "/u/XXX"
gather_facts: no
tasks:
- name: unarchive
ibm.ibm_zos_core.zos_unarchive:
src: "{{ local_directory }}/{{ backup_file }}"
dest: "{{ target_directory }}"
format:
name: tar
force: true
zos_unarchiveモジュールでは、ファイル転送と解凍を1つのタスクで実行できるようです。
上のPlaybookを実行してみます。
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_unarchive.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [unarchive USS directory] *****************************************************************************************************************************************************
TASK [unarchive] *******************************************************************************************************************************************************************
changed: [ezdwazi04] => {
"changed": true,
"dest": "/tmp/ansible.y2b1r7ro",
"dest_path": "/u/XXX",
"gid": 0,
"group": "SYS1",
"is_binary": true,
"missing": [],
"mode": "0600",
"owner": "BPXROOT",
"size": 20480,
"src": "/tmp/ansible.y2b1r7ro",
"state": "file",
"targets": [
"TEST01/subdir01",
"TEST01/subdir01/file01_01.txt",
"TEST01/subdir01/file01_02.txt",
"TEST01/subdir02",
"TEST01/subdir02/file02_01.txt",
"TEST01/subdir02/file02_02.txt",
"TEST01/subdir01/file01_02.txt",
"TEST01/subdir01/file01_01.txt",
"TEST01/subdir02/file02_01.txt",
"TEST01/subdir02/file02_02.txt"
],
"uid": 0
}
PLAY RECAP *************************************************************************************************************************************************************************
ezdwazi04 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
結果確認
IBMUSER : /u/XXX : > ls -laRT TEST01
TEST01:
total 64
drwxr-xr-x 4 BPXROOT SYS1 8192 Apr 28 00:35 .
drwxr-xr-x 3 BPXROOT SYS1 8192 Apr 28 00:35 ..
drwxr-xr-x 2 BPXROOT SYS1 8192 Apr 28 00:35 subdir01
drwxr-xr-x 2 BPXROOT SYS1 8192 Apr 28 00:35 subdir02
TEST01/subdir01:
total 36
drwxr-xr-x 2 BPXROOT SYS1 8192 Apr 28 00:35 .
drwxr-xr-x 4 BPXROOT SYS1 8192 Apr 28 00:35 ..
t IBM-1047 T=on -rw-r--r-- 1 BPXROOT SYS1 4 Apr 28 00:17 file01_01.txt
t IBM-1047 T=on -rw-r--r-- 1 BPXROOT SYS1 4 Apr 28 00:17 file01_02.txt
TEST01/subdir02:
total 36
drwxr-xr-x 2 BPXROOT SYS1 8192 Apr 28 00:35 .
drwxr-xr-x 4 BPXROOT SYS1 8192 Apr 28 00:35 ..
t IBM-1047 T=on -rw-r--r-- 1 BPXROOT SYS1 4 Apr 28 00:17 file02_01.txt
t IBM-1047 T=on -rw-r--r-- 1 BPXROOT SYS1 4 Apr 28 00:17 file02_02.txt
先にtarで固められたディレクトリがターゲットのディレクトリ先に展開されました。
USS上でのスクリプト実行
zos_scriptモジュールを使用すると、USS上でスクリプトを実行することができます。
ここでは、Jinja2テンプレートを使用したシェル・スクリプトの雛形を用意してそれを実行するPlaybookを作成してみます。
まずは実行したいスクリプトのJinja2テンプレートを用意します。ここではテスト用に単純なディレクトリを作成するだけのシェル・スクリプトを作成します。
#!/bin/sh
mkdir -p {{ new_dir }}
作成するディレクトリは変数化しています。
これを実行するためのPlaybookを作成します。
- name: execute USS script
hosts: ezdwazi04
environment: "{{ environment_vars }}"
vars:
new_dir: "/tmp/AAA"
gather_facts: no
tasks:
- name: execute script
ibm.ibm_zos_core.zos_script:
cmd: "{{ playbook_dir }}/templates/create_dir.sh"
use_template: true
上のPLaybookを実行してみます。
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_script.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [execute USS script] **********************************************************************************************************************************************************
TASK [execute script] **************************************************************************************************************************************************************
changed: [ezdwazi04] => {
"changed": true,
"cmd": "/home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/sample/template/create_dir.sh",
"rc": 0,
"remote_cmd": "/u/ibmuser/.ansible/tmp/zos_script.dve7cwhv.create_dir.sh",
"tempfile_path": "/u/ibmuser/.ansible/tmp/zos_script.dve7cwhv.create_dir.sh"
}
PLAY RECAP *************************************************************************************************************************************************************************
ezdwazi04 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
結果確認
IBMUSER : /SYSTEM/tmp : > cd /
IBMUSER : / : > cd /tmp
IBMUSER : /SYSTEM/tmp : > ls -la | grep AAA
drwxr-xr-x 2 BPXROOT SYS1 4096 Apr 28 04:18 AAA
USS上に指定したディレクトリが作成されていることが確認できました。
7.WTORへのReply
zos_operator_action_queryモジュールを使うと、WTORのメッセージをハンドリングすることができます。
例えばSYSLOGに以下のようにWTORのメッセージが出ている状況を想定します。
ここで、WTORメッセージのReply Numberを判別してIMSに対してReplyによるコマンド投入を行うPlaybookを作成してみます。
- name: Reply to WTOR
hosts: ezdwazi04
environment: "{{ environment_vars }}"
vars:
target_job_name: "IMS15CR1"
target_message_id: "DFS996I"
#reply_command: "/DIS,ACT"
reply_command: "/DIS,STATUS,DATABASE"
gather_facts: no
tasks:
- name: get all WTOR messages
ibm.ibm_zos_core.zos_operator_action_query:
register: tmp_result_all
- name: get WTOR messages for IMS READY (DFH996I)
ibm.ibm_zos_core.zos_operator_action_query:
job_name: "{{ target_job_name }}"
message_id: "{{ target_message_id }}"
register: tmp_result
- name: debug
debug:
var: tmp_result.actions[0].number
- name: reply
ibm.ibm_zos_core.zos_operator:
cmd: "R {{ tmp_result.actions[0].number }},{{ reply_command }}"
register: tmp_result
changed_when: false
【Task1: get all WTOR messages】
動作確認のため、特にフィルターをかけずに全てのWTORメッセージを取得します。
【Task2: get WTOR messages for IMS READY (DFH996I) 】
job name, message idを明示指定して特定のWTORメッセージを取得します。
【Task3: debug】
デバッグ用に上で取得したWTORメッセージのReply番号を表示させます。
【Task4: reply】
上で取得したReply番号に対してReplyによりコマンドを投入します。ここではIMSの/DISPLAYコマンドを投入します。
上のPlaybookを実行してみます。
user01@IBM-PF3ALW3Q:~/Ansible/VSCode_workspace/my_ansible_zos_sample_test$ ansible-playbook sample/zos_operator_action_query.yml
Using /home/user01/Ansible/VSCode_workspace/my_ansible_zos_sample_test/ansible.cfg as config file
PLAY [Reply to WTOR] ***************************************************************************************************************************************************************
TASK [get all WTOR messages] *******************************************************************************************************************************************************
ok: [ezdwazi04] => {
"actions": [
{
"job_id": "STC00045",
"job_name": "IMS15CR1",
"message_id": "DFS996I",
"message_text": "DFS996I *IMS READY* IVP1",
"number": "0025",
"system": "VS01",
"type": "R"
},
{
"job_name": "CNMPROC",
"message_id": "DSI802A",
"message_text": "DSI802A CNM01 REPLY WITH VALID",
"number": "0002",
"system": "VS01",
"type": "R"
}
],
"changed": false,
"count": 2
}
TASK [get WTOR messages for IMS READY (DFH996I)] ***********************************************************************************************************************************
ok: [ezdwazi04] => {
"actions": [
{
"job_id": "STC00045",
"job_name": "IMS15CR1",
"message_id": "DFS996I",
"message_text": "DFS996I *IMS READY* IVP1",
"number": "0025",
"system": "VS01",
"type": "R"
}
],
"changed": false,
"count": 1
}
TASK [debug] ***********************************************************************************************************************************************************************
ok: [ezdwazi04] => {
"tmp_result.actions[0].number": "0025"
}
TASK [reply] ***********************************************************************************************************************************************************************
ok: [ezdwazi04] => {
"changed": false,
"cmd": "R 0025,/DIS,STATUS,DATABASE",
"content": [
"VS01 2024119 05:38:30.00 ISF031I CONSOLE IBMU0000 ACTIVATED",
"VS01 2024119 05:38:30.00 -R 0025,/DIS,STATUS,DATABASE ",
"VS01 2024119 05:38:30.00 IEE600I REPLY TO 0025 IS;/DIS,STATUS,DATABASE"
],
"elapsed": 1.02,
"rc": 0,
"wait_time_s": 1
}
PLAY RECAP *************************************************************************************************************************************************************************
ezdwazi04 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
DFS996I(IMS Ready)のWTORに対してReplyによりコマンド投入されたことが確認できました。
※今回はReplyの動作確認のために上のようなPlaybookでIMSに対してReply実行してみましたが、IMS管理用に提供されている IBM z/OS IMS collection提供のモジュールを使用すればもう少しスマートにコマンド投入できそうです。
参考: ims_commandモジュール