1

我一直在尝试通过 Ansible 管理 /etc/exports。

我有一个在 VM 上安装软件的角色,然后我想在 NFS 服务器上为该特定 VM 添加一个条目 ot /etc/exports,以便它能够访问所需的 NFS 共享。

Lineinfile 听起来像是要走的路,但到目前为止我不知道如何正确编写它。

我想要这个:

  • 不修改如果主机在行,无论在哪里
  • 如果没有 NFS 共享行,则添加 NFS 共享和主机
  • 将主机添加到共享中,以防它不在其中。

我的“添加到 /etc/exports”的最新部分认为应该有效,但无效的是:

- name: Add hosts to mountpoint line
  ansible.builtin.lineinfile:
    path: /etc/exports
    line: '\1 {{ host_ip }}(root_squash,no_subtree_check)'
    regex: '^((?!{{ volume_mountpoint }}.*{{ host_ip }}\(root_squash,no_subtree_check\).*).*)$'
    backrefs: yes

但我仍然得到各种奇怪的副作用。我以前使用过反向引用等,但不知何故,这个总是让我绊倒。

任何人都看到出了什么问题?

典型的 /etc/exports 条目:

/srv/files    172.16.0.14(rw,no_root_squash,no_subtree_check)
4

1 回答 1

1

不可能在一个步骤中使用反向引用修改一行,或者如果缺少该行则添加该行。要修改现有的挂载点,需要反向引用。例如,给定测试文件

shell> cat etc/export1
/srv/files    172.16.0.14(rw,no_root_squash,no_subtree_check)

shell> cat etc/export2
/srv/files    172.16.0.15(rw,no_root_squash,no_subtree_check)

shell> cat etc/export3
/srv/download    172.16.0.14(rw,no_root_squash,no_subtree_check)

任务

  tasks:
    - lineinfile:
        path: "etc/{{ item }}"
        regex: '^{{ mount }}(\s+)({{ ipr }})*({{ optionsr }})*(\s*)(.*)$'
        line: '{{ mount }}\g<1>{{ ip }}{{ options }} \g<5>'
        backrefs: true
      vars:
        mount: /srv/files
        ipr: '172\.16\.0\.14'
        ip: '172.16.0.14'
        optionsr: '\(.*?\)'
        options: '(root_squash,no_subtree_check)'
      loop:
        - export1
        - export2
        - export3

--- before: etc/export1 (content)
+++ after: etc/export1 (content)
@@ -1 +1 @@
-/srv/files    172.16.0.14(rw,no_root_squash,no_subtree_check)
+/srv/files    172.16.0.14(root_squash,no_subtree_check) 

changed: [localhost] => (item=export1)
--- before: etc/export2 (content)
+++ after: etc/export2 (content)
@@ -1 +1 @@
-/srv/files    172.16.0.15(rw,no_root_squash,no_subtree_check)
+/srv/files    172.16.0.14(root_squash,no_subtree_check) 172.16.0.15(rw,no_root_squash,no_subtree_check)

changed: [localhost] => (item=export2)
ok: [localhost] => (item=export3)

前两个文件没问题。问题是第三个文件。该行尚未添加到文件中。从backrefs引用

“...如果正则表达式在文件中的任何地方都不匹配,则文件将保持不变。”

解释很简单。如果正则表达式不匹配,则没有组。如果没有组,则无法创建该行。

另一方面,引用正则表达式

...如果正则表达式不匹配,则该行将添加到文件中...

因此,如果正则表达式不匹配,则无法要求lineinfile添加一行,同时,如果正则表达式匹配,则不执行任何操作。如果正则表达式匹配,则需要反向引用。如果您使用反向引用,则不能添加缺失的行。

为了解决这个问题,读取文件的内容并创建一个字典

    - command: "cat etc/{{ item }}"
      register: result
      loop: [export1, export2, export3]
    - set_fact:
        content: "{{ dict(_files|zip(_lines)) }}"
      vars:
        _lines: "{{ result.results|map(attribute='stdout_lines')|list }}"
        _files: "{{ result.results|map(attribute='item')|list }}"

  content:
    export1:
    - /srv/files    172.16.0.14(rw,no_root_squash,no_subtree_check)
    export2:
    - /srv/files    172.16.0.15(rw,no_root_squash,no_subtree_check)
    export3:
    - /srv/download    172.16.0.14(rw,no_root_squash,no_subtree_check)

现在仅在缺少时添加该行,即如果安装点已经存在则不要替换该行

   - lineinfile:
        path: "etc/{{ item }}"
        line: '{{ mount }} {{ ip }}{{ options }}'
      vars:
        mount: /srv/files
        ip: '172.16.0.14'
        options: '(root_squash,no_subtree_check)'
      loop: "{{ content|list }}"
      when: content[item]|select('search', mount)|length == 0

skipping: [localhost] => (item=export1) 
skipping: [localhost] => (item=export2) 
--- before: etc/export3 (content)
+++ after: etc/export3 (content)
@@ -1 +1,2 @@
 /srv/download    172.16.0.14(rw,no_root_squash,no_subtree_check)
+/srv/files 172.16.0.14(root_squash,no_subtree_check)
于 2021-07-26T02:49:25.387 回答