我希望测试在 z/OS 下运行的 JDBC 服务器实现。通常的方法是定义一个 JCL 过程并将其作为启动任务运行。启动任务需要运行该任务的用户 ID。JDBC jar 放置在已安装在 OMVS 中的 ZFS 文件系统中。
启动任务的用户需要特定的 RACF 权限,该权限由以下 JCL 提供
//RUNRACF EXEC PGM=IKJEFT01
//SYSUADS DD DSN=SYS1.UADS,DISP=SHR
//SYSLBC DD DSN=SYS1.BRODCAST,DISP=SHR
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
AU JDBCUSR NAME('JDBC STC USER') PASSWORD(JDBCUSR) -
OWNER(IBMUSER) DFLTGRP(STCGROUP) -
UACC(READ) OMVS(HOME(/u/zfs4svr) PROGRAM(/bin/sh) UID(3005) -
FILEPROCMAX(131072))
RDEFINE STARTED SVRPROC.** STDATA(USER(JDBCUSR) GROUP(STCGROUP) -
TRUSTED(NO))
SETROPTS CLASSACT(STARTED)
SETROPTS RACLIST(STARTED) REFRESH
PERMIT BPX.SERVER ACCESS(READ) CLASS(FACILITY) -
ID(JDBCUSR)
SETROPTS CLASSACT(FACILITY)
SETROPTS RACLIST(FACILITY) REFRESH
当我启动任务时,SYSOUT 中出现以下错误消息:
JVMJZBL1001N JZOS 批处理启动器版本:2.4.4 2013-05-07
JVMJZBL1002N (C) 版权所有 IBM Corp. 2005, 2012
JVMJZBL1009E 子 shell 进程退出时未打印环境;//STDENV 不应包含“exit”JVMJZBL1042E JZOS 批处理启动器失败,返回代码 = 101
在查阅了这篇文章并阅读了IBM 支持文档不得不说,我和我的同事们都很困惑。然后我尝试将服务器作为一项直接的作业启动。该作业的用户具有系统管理员权限。这有效,我们可以测试 JDBC 服务器。尝试使用该过程的用户运行该作业会导致与上面所示的相同错误。
很明显,JDBCUSR 缺少某些权限。要将服务器作为启动任务运行,我需要知道缺少哪些权限。我们当然不希望授予启动任务用户系统管理员权限。
有没有什么办法可以找出丢失的东西?这很令人沮丧。
编辑 2016.10.11
<user>
以下 JCL 是在具有系统管理员权限时执行工作的 JOB :
//V4JSRV JOB USER=<user>,PASSWORD=<password>,REGION=200M
//*
//*******************************************************************
//* Call the server as a job
//*******************************************************************
//PROCS JCLLIB ORDER=(ACHIM.JDBCSRV.CNTL)
//SRV EXEC PROC=SRVPROC
//STDENV DD DISP=SHR,DSN=ACHIM.JDBCSRV.CNTL(SRVENV)
//STRCTREP DD DISP=SHR,DSN=ACHIM.JDBCSRV.STRCTREP
该过程如下:
//JDBCPROC PROC JAVACLS='de.ubs.du.jdbcserver.Server',
// ARGS='-p 5431 LOG-LEVEL=FINE',
// LEPARM='',
// LOGLVL='+T'
//JAVAJVM EXEC PGM=JVMLDM70,REGION=200M,
// PARM='&LEPARM/&LOGLVL &JAVACLS &ARGS'
//*JDBCPROC PROC
//*JAVAJVM EXEC PGM=JVMLDM70,REGION=200M,
//* PARM='de.ubs.du.jdbcserver.Server -p 5431 LOG-LEVEL=FINE'
//STEPLIB DD DSN=JVA700.SIEALNKE,DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSOUT DD SYSOUT=*
//STDOUT DD SYSOUT=*
//STDERR DD SYSOUT=*
//CEEDUMP DD SYSOUT=*
//ABNLIGNR DD DUMMY
如您所见,该作业只执行运行该过程的操作。当<user>
启动过程的用户名是 时,会产生上述错误,当用户名是管理员时,作业将正常运行。显然,要将其作为启动任务启动,需要将过程复制到公共过程库(准确地说是 USER.PROCLIB)。
这一切并没有什么特别引人注目的地方。事实上,这很平庸。这就是为什么我们怀疑这是一个 RACF 问题。
编辑 (2) 2016.10.11
目前这还不是解决方案,但我已经设法将问题定位。如果已分配 TRUSTED 属性,则启动的程序将运行。这实际上意味着已启动的任务在 z/OS Unix 中被视为“超级用户”(换句话说,它具有 root 权限)。因此,现在的问题就是确定我们的服务器需要什么,到目前为止,只有由超级用户运行时才可用。当我找到答案时,我会发布解决方案。
编辑 (3) 2016.12.12
添加跟踪后(参见上面修改后的过程),出现以下错误:
JVMJZBL2999T ->invokeMain() JVMJZBL2999T javaClassName: 'de.ubs.du.jdbcserver.Server' JVMJZBL2999T Arg 1='-p' JVMJZBL2999T Arg 2='5431' JVMJZBL2999T Arg 3='LOG-LEVEL=FINE' JVMJZBL1023N Invoking de.ubs.du.jdbcserver.Server.main()... JVMJZBL1056I Arguments to main... JVMJZBL1057I -p JVMJZBL1057I 5431 JVMJZBL1057I LOG-LEVEL=FINE JVMJZBL2999T -> JniUtil.convert() JVMJZBL2999T <- JniUtil.convert() JVMJZBL2008E Could not find or load class: de.ubs.du.jdbcserver.Server JVMJZBL2999T -> JniUtil.writeStackTrace() JVMJZBL2007E Stack trace follows: java.lang.NoClassDefFoundError: de.ubs.du.jdbcserver.Server Caused by: java.lang.ClassNotFoundException: de.ubs.du.jdbcserver.Server .at java.net.URLClassLoader.findClass(URLClassLoader.java:588) .at java.lang.ClassLoader.loadClassHelper(ClassLoader.java:756) .at java.lang.ClassLoader.loadClass(ClassLoader.java:724) .at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:313) .at java.lang.ClassLoader.loadClass(ClassLoader.java:703) JVMJZBL2999T <- JniUtil.writeStackTrace() JVMJZBL2999T <- invokeMain() JVMJZBL2999T <- run() JVMJZBL2999T -> cleanup() JVMJZBL1014I Waiting for non-deamon Java threads to finish before exiting... JVMJZBL2999T JvmExitHook entered with exitCode=0, javaMainReturnedOrThrewException=0 JVMJZBL1042E JZOS batch launcher failed, return code=100 JVMJZBL2999T DestroyJavaVM elapsed time=0.031311 seconds, cpu time=0.021000 seconds JVMJZBL2999I JZOS batch launcher elapsed time=7 seconds, cpu time=5.090000 seconds JVMJZBL1047W JZOS batch launcher completed with Java exception, return code=100 JVMJZBL2999T <- cleanup()
我们为什么会遇到这个运行时错误还不清楚。目前看来,它不再是权限问题。
答案1
我终于有时间回过头来研究这个问题了。最初的问题相当模糊。在查看了多个论坛后,我终于明白了成员 ACHIM.JDBCSRV.CNTL(SRVENV) 中存在错误。它包含以下行:
. /etc/profile
删除此设置可修复第一个错误,该错误是由任何 bash 脚本末尾的隐式“退出”引起的。如果您正在执行类似操作并且确实需要脚本中的设置/etc/profile
,那么我只能建议您将脚本的内容复制到您的//STDENV
数据中。
随后出现了新的错误:
java.lang.NoClassDefFoundError: de.ubs.du.jdbcserver.Server
这在上面的编辑 (3) 中有所显示。这确实是权限问题。在设置 RACF 权限的作业中,SYSTSIN DD 中有以下内容:
OMVS(HOME(/u/zfs4svr)...
当任务启动时,这将指定包含 JDBCUSR 使用的 jar 的 ZFS 文件系统的挂载点。相应的挂载作业由管理员用户运行。相关作业步骤如下:
//REPRO EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DELETE '<HLQ>.JDBCSRV.ZFS'
SET MAXCC = 0
DEFINE CLUSTER ( -
NAME('<HLQ>.JDBCSRV.ZFS') -
LINEAR CYL(50 1) -
SHAREOPTIONS(3,3) -
)
REPRO INDATASET(<HLQ>.JDBCSRV.REPRO) -
OUTDATASET(<HLQ>.JDBCSRV.ZFS)
//****************************************************
//SHELLCMD EXEC PGM=BPXBATCH,COND=(4,LT),
// PARM='SH mkdir -p /u/zfs4fb'
//SYSPRINT DD SYSOUT=*
//SYSOUT DD SYSOUT=*
//STDOUT DD SYSOUT=*
//STDERR DD SYSOUT=*
//*************************************************
//SHELLCMD EXEC PGM=BPXBATCH,COND=(4,LT),
// PARM='SH chown -R JDBCUSR:STCGROUP /u/zfs4fb'
//SYSPRINT DD SYSOUT=*
//SYSOUT DD SYSOUT=*
//STDOUT DD SYSOUT=*
//STDERR DD SYSOUT=*
//**************************************************
//SHELLCMD EXEC PGM=BPXBATCH,COND=(4,LT),
// PARM='SH chmod -R 770 /u/zfs4fb'
//SYSPRINT DD SYSOUT=*
//SYSOUT DD SYSOUT=*
//STDOUT DD SYSOUT=*
//STDERR DD SYSOUT=*
//**************************************************
//MOUNT EXEC PGM=IKJEFT01,COND=(4,LT)
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
MOUNT -
FILESYSTEM('''<HLQ>.JDBCSRV.ZFS''') -
TYPE(HFS) -
MODE(RDWR) -
MOUNTPOINT('/u/zfs4fb')
这里的难点在于,虽然 的所有者和权限/u/zfs4fb
设置为允许 JDBCUSR 访问,但是,其中的包仍然归运行该作业的用户所有。我们直接在 OMVS 中更改了内容的读/写访问权限。这解决了问题。要在脚本中修复此问题,需要更改作业步骤的顺序。在这种情况下,将 2 个//SHELCMD
步骤与chmod
和chown
命令放在//MOUNT
步骤之后可以解决问题
我们的任务还存在其他问题。在服务器初始化过程中,user.dir
使用了该属性。我不确定具体在哪里,但似乎与 z/OS 的 JVM 有关。我们花了些时间研究,因为我们无法确定该值的来源。当作为管理员用户 (IBMUSER) 提交的作业运行时,该值为“/u/ibmuser”。但是,当作为已启动任务运行时,该值为“。”,这会导致错误:
java.lang.ExceptionInInitializerError
.at java.lang.J9VMInternals.initialize(J9VMInternals.java:258)
...
Caused by: java.lang.RuntimeException: default directory must be absolute
.at sun.nio.fs.UnixFileSystem.<init>(UnixFileSystem.java:55)
...
解决方法是将命令放在环境脚本cd /u/zfs4fb
的末尾//STDENV
。这实际上可以是 STC 用户(在本例中为 JDBCUSR)有读取权限的任何目录。
希望这次探索之旅能够帮助其他试图解决类似问题的人。