te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>ansible - "Failed to import the required Python library (firewall)", using a venv with Galaxy Collections insi
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ansible - "Failed to import the required Python library (firewall)", using a venv with Galaxy Collections insi

programmeradmin3浏览0评论

I have an Ansible playbook using a role that should do some basic Linux setup tasks.

  • OS: Oracle Linux 9.5 (so, basically RHEL)
  • Ansible 2.14
  • ansible.posix 1.5.4 (hard dependency)
  • Python 3.9
  • Ansible controller and target are the same; connection is local.

All ran fine until I started to use a Python virtual environment, with the goal to encapsulate all dependencies in it, including Ansible-Galaxy Collections. I set ANSIBLE_COLLECTIONS_PATH=/home/ansible/ansible-oracle/.venv/lib/collections to point to the venv.

The moment I removed all those Collections from /usr/share, one single part of this playbook ran into the following error:

fatal: [host01]: FAILED! => changed=false
  msg: Failed to import the required Python library (firewall) on host01's Python /home/ansible/ansible-oracle/.venv/bin/python3.9. Please read the module documentation and install it in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter. Version 0.2.11 or newer required (0.3.9 or newer for offline operations)

The strange thing is, there are other Galaxy Collections used in the playbook (e.g., community.general) which do just fine. The only task that breaks is the one with ansible.posix.firewalld.

The playbook is as simple as this:

- hosts: "{{ hostgroup | default('all') }}"
  become: yes
  roles:
    - basic-linux

And here's the task causing the error:

- name: allow connections on oracle database default port
  ansible.posix.firewalld:
    port: 1521/tcp
    permanent: true
    immediate: true
    state: enabled

Check for a possible version mismatch:

$ ansible --version | grep "python version"
  python version = 3.9.19 (main, Aug 23 2024, 00:00:00) [GCC 11.5.0 20240719 (Red Hat 11.5.0-2.0.1)] (/usr/bin/python3)
$ python --version
Python 3.9.19
$ /usr/bin/python --version
Python 3.9.19

When I install the Collections globally (read: /usr/share/...), the task runs just fine. But I need a self-contained environment that doesn't break when someone upgrades something global.

While researching I stumbled upon this suggestion and modified the task to look like this (last 2 lines added):

- name: allow connections on oracle database default port
  ansible.posix.firewalld:
    port: 1521/tcp
    permanent: true
    immediate: true
    state: enabled
  vars:
    ansible_python_interpreter: /usr/bin/python

Then it runs, but why?

As the Ansible host and the target host are one and the same, the Python versions used are also identical. This even applies to the venv for now, because Python in the venv was installed from the same source (the OS install ISO image). Also, when the Collections are installed in /usr/share, they would still use the same Python version, or not? And why is only ansible.posix.firewalld affected but not community.general.*?

Before you point me to the loads of answers to similar questions: I've reviewed what I could find, but there never was a fitting explanation for my particular issue. That is: the moment ansible_python_interpreter: /usr/bin/python is set instead of the default python3, it works.

Edit: My best guess is that this has to do with the host connection being defined as 'local':

---
all:
  children:
    test:
      hosts:
        host01:
          ansible_host: local
          ansible_connection: local

When I change it to an SSH connection it runs without said error as well.

Could it be that on "local" connections, the venv settings are used while running in the target context? That would be sub-optimal.

Can anyone confirm my guess? If so, can the local connect be changed to behave like the ssh connect (e.g., use python from $PATH)?

I have an Ansible playbook using a role that should do some basic Linux setup tasks.

  • OS: Oracle Linux 9.5 (so, basically RHEL)
  • Ansible 2.14
  • ansible.posix 1.5.4 (hard dependency)
  • Python 3.9
  • Ansible controller and target are the same; connection is local.

All ran fine until I started to use a Python virtual environment, with the goal to encapsulate all dependencies in it, including Ansible-Galaxy Collections. I set ANSIBLE_COLLECTIONS_PATH=/home/ansible/ansible-oracle/.venv/lib/collections to point to the venv.

The moment I removed all those Collections from /usr/share, one single part of this playbook ran into the following error:

fatal: [host01]: FAILED! => changed=false
  msg: Failed to import the required Python library (firewall) on host01's Python /home/ansible/ansible-oracle/.venv/bin/python3.9. Please read the module documentation and install it in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter. Version 0.2.11 or newer required (0.3.9 or newer for offline operations)

The strange thing is, there are other Galaxy Collections used in the playbook (e.g., community.general) which do just fine. The only task that breaks is the one with ansible.posix.firewalld.

The playbook is as simple as this:

- hosts: "{{ hostgroup | default('all') }}"
  become: yes
  roles:
    - basic-linux

And here's the task causing the error:

- name: allow connections on oracle database default port
  ansible.posix.firewalld:
    port: 1521/tcp
    permanent: true
    immediate: true
    state: enabled

Check for a possible version mismatch:

$ ansible --version | grep "python version"
  python version = 3.9.19 (main, Aug 23 2024, 00:00:00) [GCC 11.5.0 20240719 (Red Hat 11.5.0-2.0.1)] (/usr/bin/python3)
$ python --version
Python 3.9.19
$ /usr/bin/python --version
Python 3.9.19

When I install the Collections globally (read: /usr/share/...), the task runs just fine. But I need a self-contained environment that doesn't break when someone upgrades something global.

While researching I stumbled upon this suggestion and modified the task to look like this (last 2 lines added):

- name: allow connections on oracle database default port
  ansible.posix.firewalld:
    port: 1521/tcp
    permanent: true
    immediate: true
    state: enabled
  vars:
    ansible_python_interpreter: /usr/bin/python

Then it runs, but why?

As the Ansible host and the target host are one and the same, the Python versions used are also identical. This even applies to the venv for now, because Python in the venv was installed from the same source (the OS install ISO image). Also, when the Collections are installed in /usr/share, they would still use the same Python version, or not? And why is only ansible.posix.firewalld affected but not community.general.*?

Before you point me to the loads of answers to similar questions: I've reviewed what I could find, but there never was a fitting explanation for my particular issue. That is: the moment ansible_python_interpreter: /usr/bin/python is set instead of the default python3, it works.

Edit: My best guess is that this has to do with the host connection being defined as 'local':

---
all:
  children:
    test:
      hosts:
        host01:
          ansible_host: local
          ansible_connection: local

When I change it to an SSH connection it runs without said error as well.

Could it be that on "local" connections, the venv settings are used while running in the target context? That would be sub-optimal.

Can anyone confirm my guess? If so, can the local connect be changed to behave like the ssh connect (e.g., use python from $PATH)?

Share Improve this question edited Feb 18 at 8:46 Uwe asked Feb 17 at 19:22 UweUwe 214 bronze badges 2
  • Can you further isolate the problem? In particular, I wonder if you can reproduce it in a local venv. See also minimal reproducible example. – Ulrich Eckhardt Commented Feb 18 at 8:52
  • Thanks @UlrichEckhardt, I checked a bit more on the topic of SSH vs. local connections and think I found the difference in behaviour and a mitigation. Will post an answer to myself shortly. – Uwe Commented 2 days ago
Add a comment  | 

1 Answer 1

Reset to default 2

Well... looks like this is yet another example of "communicating the problem helps understanding it". I was already on the right track with my assumption that local connections are treated differently than remote ones.

After reading the Ansible docs more closely (namely Running against localhost and Controlling where tasks run), it became clear to me that on local connections, Ansible tries to run the same Python interpreter as in its own (virtual) environment.

Additionally to my error message above, this can also result in a "permission denied" when Ansible becomes another user that hasn't permissions to files in the (virtual) environment of the Ansible user.

Solution:

Configure the host in the inventory with an explicit setting for the Python interpreter to use. E. g., "/usr/bin/env python" or "{{ ansible_playbook_python }}".

In my example above, this runs with the host entry:

---
all:
  children:
    test:
      hosts:
        host01:
          ansible_host: local
          ansible_connection: local
          ansible_python_interpreter: "{{ ansible_playbook_python }}"
发布评论

评论列表(0)

  1. 暂无评论