使用 Ansible 管理 z/OS UNIX 主机
Ansible 可以连接到 IBM z/OS UNIX System Services,从而将您的 Ansible 自动化策略引入 IBM z/OS。这通过与 Ansible 配置管理、置备和应用程序部署的无缝统一工作流编排,实现了 IBM Z 上的开发和运维自动化。
Ansible 与 z/OS UNIX System Services
UNIX System Services 可以支持 Ansible 受管节点所需的依赖项,包括运行 Python 以及通过 SSH 连接生成交互式 Shell 进程。Ansible 可以将 UNIX System Services 节点作为目标,通过 ansible.builtin 模块来修改文件、目录等。此外,在 UNIX System Services Shell 中输入命令可以完成的任何操作,都可以记录并在 Ansible Playbook 中实现自动化。
z/OS 环境
虽然大多数系统以二进制或 UTF-8 编码文本这两种模式处理文件,但包括 UNIX System Services 在内的 IBM z/OS 还具有第三种模式:EBCDIC 编码文本。Ansible 具备处理二进制数据和 UTF-8 编码文本数据的能力,但不直接支持 EBCDIC 编码数据。这并不一定算作限制,只是需要额外的任务来将文件与其原始编码进行转换。由管理 z/OS UNIX 节点的 Ansible 用户负责了解其自动化操作中文件的性质。
文件的类型(二进制或文本)和编码可以存储在文件“标签”(tags)中。文件标签是 z/OS UNIX System Services 的一个概念(“增强型 ASCII”的一部分),旨在区分二进制文件、UTF-8 编码文本文件和 EBCDIC 编码文本文件。
未加标签的文件或流的默认行为由程序决定,例如,IBM Open Enterprise SDK for Python 默认使用 UTF-8 编码。
Ansible 模块不会读取或识别文件标签。用户有责任确定远程数据的性质并为其添加适当的标签。通过 Ansible 发送到远程 z/OS UNIX 主机的数据默认是 UTF-8 编码且未加标签的。可以使用 ansible.builtin.command 模块通过额外的任务来为文件添加标签。
- name: Tag my_file.txt as UTF-8.
ansible.builtin.command: chtag -tc iso8859-1 my_file.txt
z/OS UNIX System Services 上提供的 z/OS Shell 对于未加标签的数据流默认采用 EBCDIC 编码。Ansible 向 z/OS Shell 发送未加标签的 UTF-8 编码文本数据,而 z/OS Shell 期望未加标签的数据以 EBCDIC 编码。可以通过设置 PYTHONSTDINENCODING 环境变量来解决这种数据编码不匹配的问题,这会使 Python 使用的管道被标记为指定的编码。文件和管道标签可用于 ASCII 和 EBCDIC 之间的自动转换,但只有 z/OS UNIX 上能够识别标签的程序才会使用它们。
在 z/OS UNIX 上使用 ansible.builtin 模块
ansible.builtin 模块在操作时默认所有文本数据(文件和管道/流)均为 UTF-8 编码。在 z/OS 上,由于文本数据(文件或流)有时以 EBCDIC 编码,有时以 UTF-8 编码,因此必须特别注意确定目标数据的正确编码。
以下是在 z/OS UNIX 上使用 ansible.builtin 模块的一些说明/专家建议。这绝非详尽列表。在使用任何 Ansible 模块之前,必须先 配置远程环境。
- ansible.builtin.command / ansible.builtin.shell
command 和 shell 模块非常适合自动化那些已有命令行解决方案的任务。使用这些模块时需要记住,根据系统配置,z/OS Shell (
/bin/sh) 可能会以 EBCDIC 格式返回输出。LE 环境变量配置会在流被标记时正确转换它们,并将可读的输出返回给 Ansible。然而,某些命令行程序可能会以 UTF-8 格式返回输出但不标记管道。在这种情况下,自动转换可能会错误地假设输出是 EBCDIC 并尝试进行转换,导致输出乱码。如果已知源编码,可以使用 ansible.builtin.shell 模块通过管道链接命令的功能,将输出传送到iconv。在此示例中,您可能需要为“转换前”和“转换后”选择代表您文件编码的其他编码。ansible.builtin.shell: "some_pgm | iconv -f ibm-1047 -t iso8859-1"
- ansible.builtin.raw
raw 模块在设计上会忽略所有远程环境设置。但是,z/OS UNIX System Services 受管节点需要一些基础配置。要在 UNIX System Services 上使用此模块,请在所需命令之前将最小环境变量配置为一系列 export 语句。
ansible.builtin.raw: | export _BPXK_AUTOCVT: "ON" ; export _CEE_RUNOPTS: "FILETAG(AUTOCVT,AUTOTAG) POSIX(ON)" ; export _TAG_REDIR_ERR: "txt" ; export _TAG_REDIR_IN: "txt" ; export _TAG_REDIR_OUT: "txt" ; echo "hello world!"
或者,考虑使用上面提到的 ansible.builtin.command 或 ansible.builtin.shell 模块,它们会为每个任务设置配置好的远程环境。
- ansible.builtin.copy / ansible.builtin.fetch
ansible.builtin模块不会自动标记文件,现有的文件标签也不会被保留。在运行 copy/fetch 操作时,您可以将文件视为二进制文件,这样在数据完整性方面没有问题,但请记住在文件传回 z/OS UNIX 后恢复文件标签,因为标签不会被保留。请使用 command 模块来设置文件标签。- name: Tag my_file.txt as UTF-8. ansible.builtin.command: chtag -tc iso8859-1 my_file.txt
- ansible.builtin.blockinfile / ansible.builtin.lineinfile
这些模块以 UTF-8 处理所有数据。请确保目标文件事先已是 UTF-8 编码,并在之后重新为文件添加标签。
- ansible.builtin.script
内置的 script 模块会将本地脚本文件复制到远程目标上的临时文件并运行它。z/OS UNIX System Services 目标遇到的问题是,当底层的 z/OS Shell 尝试读取脚本文件时,由于文件没有被标记为 UTF-8 文本,Shell 会假设文件是以 EBCDIC 编码的,从而无法正确读取或运行脚本。一种解决方法是手动将本地文件复制到受管节点(使用 ansible.builtin.copy)并转换或标记文件(使用 ansible.builtin.command 模块)。使用这种方法会失去 script 模块的一些便利性(例如运行后自动清理脚本文件),但作为 Playbook 的额外任务来执行这些步骤非常简单。
- name: Copy local script file to remote node. ansible.builtin.copy: src: "{{ playbook_dir }}/local/scripts/sample.sh" dest: /u/ibmuser/scripts/ - name: Tag remote script file. ansible.builtin.command: "chtag -tc ISO8859-1 /u/ibmuser/scripts/sample.sh" - name: Run script. ansible.builtin.command: "/u/ibmuser/scripts/sample.sh"
另一种解决方法是将本地脚本文件存储为 EBCDIC 编码。它们在 Ansible 控制节点上可能不可读,但它们可以正确复制到 z/OS UNIX System Services 目标并正常运行。这种方法利用了 script 模块的内置便利性,但管理本地不可读的 EBCDIC 文件会增加维护脚本的难度。
配置远程环境
某些语言环境 (LE) 配置可以启用 z/OS UNIX 系统上的 Python(IBM Open Enterprise SDK for Python)所需的自动编码转换和自动文件标记功能。
在为任何 z/OS UNIX 受管节点设置远程环境时,请包含以下配置:
_BPXK_AUTOCVT: "ON"
_CEE_RUNOPTS: "FILETAG(AUTOCVT,AUTOTAG) POSIX(ON)"
_TAG_REDIR_ERR: "txt"
_TAG_REDIR_IN: "txt"
_TAG_REDIR_OUT: "txt"
Ansible 可以通过这些选项配置远程环境变量
inventory - inventory.yml, group_vars/all.yml, 或 host_vars/all.yml
playbook - Playbook 顶部的
environment变量。block 或 task -
environment关键字。
有关更多详细信息,请参阅 设置远程环境。
配置远程 Python 解释器
Ansible 需要 Python 解释器才能在远程主机上运行大多数模块,并且它会检查“默认”路径 /usr/bin/python 下是否存在 Python。
在 z/OS UNIX 上,Python3 解释器(来自 IBM Open Enterprise SDK for Python)通常安装在不同的路径中,例如:/usr/lpp/cyp/v3r12/pyz。
可以使用 Ansible 清单变量 ansible_python_interpreter 来配置 Python 解释器的路径。例如:
zos1 ansible_python_interpreter:/usr/lpp/cyp/v3r12/pyz
当在目标主机上的默认位置找不到 Python 解释器路径时,可能会出现包含以下消息的错误:/usr/bin/python: FSUM7351 not found
更多详细信息,请参阅:如何处理远程机器上 /usr/bin/python 没有 Python 解释器的情况?。
配置远程 Shell
z/OS UNIX System Services 受管节点包含多个 Shell。目前唯一支持的 Shell 是位于 /bin/sh 路径下的 z/OS Shell。要配置 Ansible 控制节点在目标节点上使用哪个 Shell,请设置清单变量 ansible_shell_executable。例如:
zos1 ansible_shell_executable=/bin/sh
启用 Ansible 流水线(Pipelining)
在 ansible.cfg 文件中启用 ANSIBLE_PIPELINING。
启用 Ansible 流水线后,Ansible 通过 Python 的 stdin 管道将任何模块代码传递到远程目标节点,并在单次调用中全部运行,而不是先将数据复制到临时文件,然后再从中读取。有关流水线的更多详细信息,请参阅:流水线。
建议启用此行为,因为 Python 会用正确的编码标记其管道,从而减少遇到编码错误的机会。此外,使用 Python stdin 管道比文件 I/O 性能更高。
在对 z/OS UNIX 受管节点执行任何任务的环境中,请包含以下内容:
PYTHONSTDINENCODING: "cp1047"
当启用 Ansible 流水线但未正确设置 PYTHONSTDINENCODING 属性时,可能会导致以下错误。注意,下面的十六进制 '\x81' 可能会因导致错误的源而异。
SyntaxError: Non-UTF-8 code starting with '\\x81' in file <stdin> on line 1, but no encoding declared; see https://peps.pythonlang.cn/pep-0263/ for details
乱码
在 Playbook 输出中看到乱码通常是 EBCDIC 编码混淆引起的。请仔细检查远程环境是否设置正确。同时检查远程节点和控制节点上的预期文件编码。ansible.builtin 模块会假定所有文本数据都是 UTF-8 编码的,而 z/OS UNIX 可能使用的是 EBCDIC。在许多 z/OS UNIX 系统上,未加标签文件的默认编码是 EBCDIC。这种默认设置的差异很容易导致数据被错误编码解析,无论是未能自动将 EBCDIC 转换为 UTF-8,还是错误地尝试转换已经以 UTF-8 编码的数据。
将 z/OS 用作控制节点
z/OS 操作系统目前无法配置为 Ansible 控制节点。尽管 z/OS UNIX System Services 接口符合 POSIX 标准,但它也不能被配置为 Ansible 控制节点。
IBM Z 平台上有多种选项可供将其用作控制节点:
IBM z/OS Container Extensions (zCX)
Red Hat OpenShift on IBM zSystems and LinuxONE
Linux on IBM Z