はじめに
Jenkinsを活用してメインフレーム・アプリケーションの管理をどのように行えるのかを探っていく連載記事です。
今回は、ごくシンプルなPipelineを作成してシェル・コマンドをz/OSに対して実行するところまでやってみます。
関連記事
Jenkins - z/OS連携: (1) 概要
Jenkins - z/OS連携: (2) Pipelineの利用
Jenkins - z/OS連携: (3) Pipeline+Gitの利用
Jenkins - z/OS連携: (4) Pipeline+Git+Webhookの利用
Jenkins - z/OS連携: (5) Pipeline+Git+DBBの利用
Jenkins - z/OS連携: (6) Jenkins Pipeline利用シナリオ
環境情報
今回、検証に利用する環境は、IBM Wazi Developer for Red Hat CodeReady WorkspacesというOpenShift上に構成されるz/OS開発環境を利用します。この製品はSandboxと呼ばれるz/OSエミュレーターを中心に各種開発ツールがバンドルされており、DBBなども含まれます。
このWaziのSandbox(z/OSエミュレーター)は、最初からDBBやGitなどが構成された状態のz/OSイメージが提供されているので、今回はそれをそのまま使います。
z/OS(Sandbox)
z/OS V2.4
Jenkins Server
Waziの手順に従い、Sandboxと同OpenShift上にJenkins Serverを構成
参考: Configuring a Jenkins server in OpenShift
Jenkins V2.235.5
Git plugin V4.2.2
Git client plugin V3.4.2
SSH Build Agents plugin V1.31.5
SSH Credentials plugin V1.18.1
シンプルなPipelineの実行
さて、まずはごくシンプルなPipelineを作ってそれをz/OSに対して流してみましょう。
Jenkins用ユーザー (z/OS)
Jenkinsからz/OSをSlaveとして管理する場合、SSH経由で制御することになるので、SSHで接続できるユーザーを用意しておきます。Jenkinsから実施される処理は基本的にこのユーザーで実行されることになります。
Jenkins:ノード構成
z/OSをJenkinsの管理対象のノードとして構成します。
ノードを構成すると対象ノードにSSH経由で接続してAgentの構成を行います。AgentはSSH経由でシェルからJavaとして実行されるので、シェルの環境変数やJVMオプションなどを指定します。
起動時の主要パラメータ補足:
パラメーター | 値 | 補足 |
---|---|---|
Javaのパス | /usr/lpp/java/J8.0_64/bin/java | |
JVMオプション | -Xquickstart -Dfile.encoding=UTF-8 -Xnoargsconversion | |
Prefix Start Agent Command | export JAVA_HOME=/usr/lpp/java/J8.0_64 && export IBM_JAVA_ENABLE_ASCII_FILETAG=ON && env && | |
Suffix Start Agent Command | -text | 先頭にブランク |
ノード接続時のログ
[03/12/21 09:31:46] [SSH] The remote user's environment is:
@="sh"
ERRNO="0"
HOME="/u/JENKIN2"
IFS="
"
LINENO="0"
LOGNAME="JENKIN2"
MAIL="/usr/mail/JENKIN2"
MAILCHECK="600"
OPTIND="1"
PATH="/bin"
PPID="50398323"
PS1="\$ "
PS2="> "
PS3="#? "
PS4="+ "
PWD="/u/JENKIN2"
RANDOM="24367"
SECONDS="0"
SHELL="/bin/sh"
SSH_CLIENT="172.26.1.1 50003 22"
SSH_CONNECTION="172.26.1.1 50003 172.26.1.2 22"
USER="JENKIN2"
[03/12/21 09:31:47] [SSH] Starting sftp client.
[03/12/21 09:31:48] [SSH] Copying latest remoting.jar...
Source agent hash is E5FEC468D6F172BF394E1F2571EA686C. Installed agent hash is E5FEC468D6F172BF394E1F2571EA686C
Verified agent jar. No update is necessary.
Expanded the channel window size to 4MB
[03/12/21 09:31:52] [SSH] Starting agent process: export JAVA_HOME=/usr/lpp/java/J8.0_64 && export IBM_JAVA_ENABLE_ASCII_FILETAG=ON && env &&cd "/u/JENKIN2/agent/wazi-test01" && /usr/lpp/java/J8.0_64/bin/java -Xquickstart -Dfile.encoding=UTF-8 -Xnoargsconversion -jar remoting.jar -workDir /u/JENKIN2/agent/wazi-test01 -jar-cache /u/JENKIN2/agent/wazi-test01/remoting/jarCache -text
MAIL=/usr/mail/JENKIN2
PATH=/bin
SSH_CLIENT=172.26.1.1 50003 22
SHELL=/bin/sh
IBM_JAVA_ENABLE_ASCII_FILETAG=ON
_=/bin/env
LOGNAME=JENKIN2
USER=JENKIN2
HOME=/u/JENKIN2
SSH_CONNECTION=172.26.1.1 50003 172.26.1.2 22
JAVA_HOME=/usr/lpp/java/J8.0_64
Running in text mode
Mar 12, 2021 9:32:47 AM org.jenkinsci.remoting.engine.WorkDirManager initializeWorkDir
INFO: Using /u/JENKIN2/agent/wazi-test01/remoting as a remoting work directory
Mar 12, 2021 9:32:49 AM org.jenkinsci.remoting.engine.WorkDirManager setupLogging
INFO: Both error and output logs will be printed to /u/JENKIN2/agent/wazi-test01/remoting
<===[JENKINS REMOTING CAPACITY]===><===[HUDSON TRANSMISSION BEGINS]===channel started
Remoting version: 4.3
This is a Unix agent
Mar 12, 2021 9:35:43 AM hudson.remoting.UserRequest perform
WARNING: LinkageError while performing UserRequest:jenkins.slaves.StandardOutputSwapper$ChannelSwapper@6884a3c3
java.lang.UnsatisfiedLinkError: Native library (com/sun/jna/z/os-s390x/libjnidispatch.so) not found in resource path ([])
at com.sun.jna.Native.loadNativeDispatchLibraryFromClasspath(Native.java:1032)
at com.sun.jna.Native.loadNativeDispatchLibrary(Native.java:988)
at com.sun.jna.Native.<clinit>(Native.java:195)
at hudson.util.jna.GNUCLibrary.<clinit>(GNUCLibrary.java:115)
at jenkins.slaves.StandardOutputSwapper$ChannelSwapper.swap(StandardOutputSwapper.java:60)
at jenkins.slaves.StandardOutputSwapper$ChannelSwapper.call(StandardOutputSwapper.java:45)
at jenkins.slaves.StandardOutputSwapper$ChannelSwapper.call(StandardOutputSwapper.java:39)
at hudson.remoting.UserRequest.perform(UserRequest.java:211)
at hudson.remoting.UserRequest.perform(UserRequest.java:54)
at hudson.remoting.Request$2.run(Request.java:369)
at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:72)
at java.util.concurrent.FutureTask.run(FutureTask.java:277)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1160)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.lang.Thread.run(Thread.java:820)
ERROR: Failed to monitor for Clock Difference
java.util.concurrent.TimeoutException
at hudson.remoting.Request$1.get(Request.java:316)
at hudson.remoting.Request$1.get(Request.java:240)
at hudson.remoting.FutureAdapter.get(FutureAdapter.java:59)
at hudson.node_monitors.AbstractAsyncNodeMonitorDescriptor.monitorDetailed(AbstractAsyncNodeMonitorDescriptor.java:114)
at hudson.node_monitors.AbstractAsyncNodeMonitorDescriptor.monitor(AbstractAsyncNodeMonitorDescriptor.java:78)
at hudson.node_monitors.AbstractNodeMonitorDescriptor$Record.run(AbstractNodeMonitorDescriptor.java:306)
ERROR: Failed to monitor for Architecture
java.util.concurrent.TimeoutException
at hudson.remoting.Request$1.get(Request.java:316)
at hudson.remoting.Request$1.get(Request.java:240)
at hudson.remoting.FutureAdapter.get(FutureAdapter.java:59)
at hudson.node_monitors.AbstractAsyncNodeMonitorDescriptor.monitorDetailed(AbstractAsyncNodeMonitorDescriptor.java:114)
at hudson.node_monitors.AbstractAsyncNodeMonitorDescriptor.monitor(AbstractAsyncNodeMonitorDescriptor.java:78)
at hudson.node_monitors.AbstractNodeMonitorDescriptor$Record.run(AbstractNodeMonitorDescriptor.java:306)
ERROR: Failed to monitor for Free Disk Space
java.util.concurrent.TimeoutException
at hudson.remoting.Request$1.get(Request.java:316)
at hudson.remoting.Request$1.get(Request.java:240)
at hudson.remoting.FutureAdapter.get(FutureAdapter.java:59)
at hudson.node_monitors.AbstractAsyncNodeMonitorDescriptor.monitorDetailed(AbstractAsyncNodeMonitorDescriptor.java:114)
at hudson.node_monitors.AbstractAsyncNodeMonitorDescriptor.monitor(AbstractAsyncNodeMonitorDescriptor.java:78)
at hudson.node_monitors.AbstractNodeMonitorDescriptor$Record.run(AbstractNodeMonitorDescriptor.java:306)
ERROR: Failed to monitor for Response Time
java.util.concurrent.TimeoutException
at hudson.remoting.Request$1.get(Request.java:316)
at hudson.remoting.Request$1.get(Request.java:240)
at hudson.remoting.FutureAdapter.get(FutureAdapter.java:59)
at hudson.node_monitors.AbstractAsyncNodeMonitorDescriptor.monitorDetailed(AbstractAsyncNodeMonitorDescriptor.java:114)
at hudson.node_monitors.ResponseTimeMonitor$1.monitor(ResponseTimeMonitor.java:57)
at hudson.node_monitors.AbstractNodeMonitorDescriptor$Record.run(AbstractNodeMonitorDescriptor.java:306)
ERROR: Failed to monitor for Free Temp Space
java.util.concurrent.TimeoutException
at hudson.remoting.Request$1.get(Request.java:316)
at hudson.remoting.Request$1.get(Request.java:240)
at hudson.remoting.FutureAdapter.get(FutureAdapter.java:59)
at hudson.node_monitors.AbstractAsyncNodeMonitorDescriptor.monitorDetailed(AbstractAsyncNodeMonitorDescriptor.java:114)
at hudson.node_monitors.AbstractAsyncNodeMonitorDescriptor.monitor(AbstractAsyncNodeMonitorDescriptor.java:78)
at hudson.node_monitors.AbstractNodeMonitorDescriptor$Record.run(AbstractNodeMonitorDescriptor.java:306)
ERROR: Failed to monitor for Free Swap Space
java.util.concurrent.TimeoutException
at hudson.remoting.Request$1.get(Request.java:316)
at hudson.remoting.Request$1.get(Request.java:240)
at hudson.remoting.FutureAdapter.get(FutureAdapter.java:59)
at hudson.node_monitors.AbstractAsyncNodeMonitorDescriptor.monitorDetailed(AbstractAsyncNodeMonitorDescriptor.java:114)
at hudson.node_monitors.AbstractAsyncNodeMonitorDescriptor.monitor(AbstractAsyncNodeMonitorDescriptor.java:78)
at hudson.node_monitors.AbstractNodeMonitorDescriptor$Record.run(AbstractNodeMonitorDescriptor.java:306)
Agent successfully connected and online
The Agent is connected, disconnect it before to try to connect it again.
Pipelineの作成
新規ジョブ作成を選択します。
名前を指定して、"パイプライン"を選択します。
Pipeline Scriptとして以下を記載します。
pipeline {
agent {label 'wazi-test01'}
stages {
stage('Hello') {
steps {
echo 'Hello World'
}
}
stage('Hello2'){
steps {
sh """
echo 'Hello World2'
hostname
pwd
"""
}
}
stage('Hello3'){
steps {
sh """
echo 'Hello World3'
ls -la
"""
}
}
}
}
先頭のagent {label 'wazi-test01'}
で、実行するノードのラベルを指定しています。
処理内容としては、3つのステージを定義し、それぞれ単純なシェル・コマンドを実行しているだけです。
Pipeline実行
ログを確認
パイプライン実行時のログ
Started by user IAM#xxxxx
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on wazi-test01 in /u/JENKIN2/agent/wazi-test01/workspace/Tag_pipeline_hello
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Hello)
[Pipeline] echo
Hello World
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Hello2)
[Pipeline] sh
+ echo Hello World2
Hello World2
+ hostname
S0W1.DAL-EBIS.IHOST.COM
+ pwd
/u/JENKIN2/agent/wazi-test01/workspace/Tag_pipeline_hello
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Hello3)
[Pipeline] sh
+ echo Hello World3
Hello World3
+ ls -la
total 16
drwxr-xr-x 2 JENKIN2 SYS1 0 Mar 12 09:53 .
drwxr-xr-x 4 JENKIN2 SYS1 8192 Mar 12 09:53 ..
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
z/OSのUSS上で指定したシェルのコマンドが実行されたのが確認できました!
ちなみに、Piplineで実行するシェル・コマンドにsleepを入れてz/OS側のファイル構造を覗いてみると、こんな感じで実行されていました。
TAGUCHI:/u/JENKIN2/agent/wazi-test01/workspace: >ls -laR
.:
total 48
drwxr-xr-x 4 JENKIN2 SYS1 8192 Mar 12 18:53 .
drwx------ 5 JENKIN2 SYS1 8192 Mar 12 18:53 ..
drwxr-xr-x 2 JENKIN2 SYS1 0 Mar 12 18:53 Tag_pipeline_hello
drwxr-xr-x 3 JENKIN2 SYS1 8192 Mar 13 10:46 Tag_pipeline_hello@tmp
./Tag_pipeline_hello:
total 16
drwxr-xr-x 2 JENKIN2 SYS1 0 Mar 12 18:53 .
drwxr-xr-x 4 JENKIN2 SYS1 8192 Mar 12 18:53 ..
./Tag_pipeline_hello@tmp:
total 48
drwxr-xr-x 3 JENKIN2 SYS1 8192 Mar 13 10:46 .
drwxr-xr-x 4 JENKIN2 SYS1 8192 Mar 12 18:53 ..
drwxr-xr-x 2 JENKIN2 SYS1 8192 Mar 13 10:46 durable-f42e8941
./Tag_pipeline_hello@tmp/durable-f42e8941:
total 66
drwxr-xr-x 2 JENKIN2 SYS1 8192 Mar 13 10:46 .
drwxr-xr-x 3 JENKIN2 SYS1 8192 Mar 13 10:46 ..
-rw-r--r-- 1 JENKIN2 SYS1 135 Mar 13 10:46 jenkins-log.txt
-rw-r--r-- 1 JENKIN2 SYS1 2 Mar 13 10:46 jenkins-result.txt
-rw-r--r-- 1 JENKIN2 SYS1 92 Mar 13 10:46 script.sh
TAGUCHI:/u/JENKIN2/agent/wazi-test01/workspace: >cat *tmp/d*/script.sh
echo 'Hello World3'
sleep 20
ls -la
workspace以下にtempのディレクトリが作成されて、pipelineのstepで指定されたシェル・コマンドがscript.shというファイルとして作成されていました。
Pipeline実行後はこれらのファイルは削除されています。
まとめ
シンプルな例なので非常に分かりやすいですね。