如何基于主机条件性使用特定上下文的ansible_python_interpreter?
如何基于主机条件性使用特定上下文的ansible_python_interpreter?
最近我碰到了个特别头疼的Ansible问题,跟大家唠唠来龙去脉和我折腾的过程:
之前我的Ansible Playbook突然集体罢工,查了半天发现是RedHat回滚的某个CVE补丁搞的鬼——这个补丁和系统里Python的docker-py库(靠requests组件依赖)不兼容。docker-py的7.1.0版本修复了这个问题,但它要求Python 3.8才行,可服务器根本没法升级到3.8:我们其他任务还依赖selinux,而这个包只支持Python 3.6。
思来想去,结论只能是:不同任务用不同的Python环境。本来以为这事很简单,只要在任务里指定解释器就行,比如处理Docker相关的任务我这么写:
- name: 获取{{ fully_qualified_image }}镜像的已有副本信息 community.docker.docker_image_info: name: "{{ fully_qualified_image }}" register: preexisting_image_info failed_when: false vars: # ansible_python_interpreter_docker指向装有Docker依赖库的Python虚拟环境 ansible_python_interpreter: "{{ ansible_python_interpreter_docker }}"
但麻烦的是,不是所有主机都需要这个特殊虚拟环境,有些用系统默认的Python就够了。于是我在group_vars/all/vars.yml里做了个默认配置:
ansible_python_interpreter_docker: "{{ ansible_python_interpreter }}"
打算给需要特殊解释器的主机单独覆盖这个变量就行。结果倒好,需要特殊环境的主机跑起来没问题,但用默认配置的主机直接触发了无限递归错误,日志长这样:
... Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ ansible_python_interpreter }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ ansible_python_interpreter_docker }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: recursive loop detected in template string: {{ ansible_python_interpreter_docker }}"
没办法,我先凑合用了个临时的workaround,写了个测试Playbook能跑通:
--- - hosts: host-with-system-docker,host-with-venv-docker gather_facts: true tasks: - block: - name: 用系统Python执行Docker操作 debug: msg: "{{ ansible_python_interpreter }}" when: ansible_python_interpreter_docker is not defined - name: 用Docker专用Python环境执行操作 debug: msg: "{{ ansible_python_interpreter }}" vars: ansible_python_interpreter: "{{ ansible_python_interpreter_docker }}" when: ansible_python_interpreter_docker is defined - debug: msg: "YAY"
不过这写法实在太啰嗦,后来有人建议我用omit来简化,我赶紧试了这么写:
--- - hosts: host-with-system-docker,host-with-venv-docker gather_facts: true tasks: - block: - name: 不覆盖解释器的情况 debug: msg: "{{ ansible_python_interpreter }}" - name: 用omit尝试动态处理解释器 debug: msg: "{{ ansible_python_interpreter }}" vars: ansible_python_interpreter: "{{ ansible_python_interpreter_docker | default(omit) }}"
结果跑出来的结果离谱到我懵圈,完全不符合预期:
TASK [不覆盖解释器的情况] **************************************************************************************************************************************************************************************************************************************************************************** Monday 27 January 2025 10:18:24 -0500 (0:00:02.976) 0:00:03.062 ******** ok: [host-with-venv-docker] => { "msg": "/usr/bin/python3" } ok: [host-with-system-docker] => { "msg": "/home/ltheisen/.ansible-venvs/d58c1d218f1f70fa8eedf52a851e15d9/bin/python" } TASK [用omit尝试动态处理解释器] **************************************************************************************************************************************************************************************************************************************************************************************** Monday 27 January 2025 10:18:24 -0500 (0:00:00.071) 0:00:03.134 ******** ok: [host-with-venv-docker] => { "msg": "/usr/local/lib/ansible/python3.8-venv-docker/bin/python" } ok: [host-with-system-docker] => { "msg": "Hello world!" }
你看,用omit的任务里,本该输出默认解释器的主机,结果居然打出了"Hello world!",这完全是驴唇不对马嘴。现在我还在找更优雅的解决方法,有没有大佬给支个招?
备注:内容来源于stack exchange,提问作者Lucas
相关产品推荐
相关产品推荐

