Ansible:如何通过在主机上附加文件的任务实现幂等性(不恢复到初始状态)

发布于 2025-01-11 12:17:35 字数 1608 浏览 0 评论 0原文

我很难了解如何创建遵循文档中最佳实践的 Ansible 角色。我正在研究的以下用例是在主机上启用 Filebeat。可以通过将模块定义放置在 /etc/filebeat/modules.d 文件夹中来配置 Filebeat。

当我添加模块时它工作得很好。幂等性每次运行时都会起作用,在角色(剧本)的每次运行中都会启用一组给定的模块。

但是,当我决定不再需要某个给定模块时,我应该做什么?我将其从角色中删除,重新运行剧本,以便启用所有其他模块。 但是:之前的运行启用了一个模块,在更改后我没有直接使用角色安装该模块。因此,我的服务器状态仍然以与角色本身强加的方式不同的方式改变。

我的问题是:我应该在应用模块之前删除模块,以便我总是从新鲜状态开始吗?

例如:

- name: Remove modules
  file:
    dest: "/etc/filebeat/modules.d/{{ item }}"
    state: absent
  loop:
    - "module1.yml"
    - "module2.yml"
    - "module3.yml" # It was being installed in previous role, but not now

- name: Enable modules via 'modules.d' directory
  template:
    src: "modules.d/{{ item }}"
    dest: "/etc/filebeat/modules.d/{{ item }}"
    mode: '0644'
  loop:
    - "module1.yml"
    - "module2.yml"

所以我删除了 module3.yml,因为我记得我之前安装过它,并安装了 module1.ymlmodule2.yml

而不是只安装我需要的东西,无论之前安装了什么:

- name: Enable modules via 'modules.d' directory
  template:
    src: "modules.d/{{ item }}"
    dest: "/etc/filebeat/modules.d/{{ item }}"
    mode: '0644'
  loop:
    - "module1.yml"
    - "module2.yml"

给我留下 module1.ymlmodule2.yml (所需),不幸的是:module3.yml(来自之前的角色)。

如何管理以避免此类情况?并避免将服务器视为一台大型有状态机器,即使我运行一个角色,输出也与预期不同,因为之前已经完成了一些操作,我在当前的 Ansible 角色代码中看不到。

您是否在 Ansible 工作流程中编写revert playbook 以便在需要时恢复到初始状态?

我很好奇。预先感谢您的回复。

I am having a hard time getting to know how to create Ansible roles that are following the best practices according to documentation. The following use-case which I am looking at is e.g. enabling Filebeat on host. Filebeat can be configured by placing a module definition in /etc/filebeat/modules.d folder.

It works fine when I am adding modules. Idempotence is working, everytime, on each run of the role (playbook), a given set of modules is enabled.

But what I should do when I decide that a given module is not longer needed? I remove it from role, rerun a playbook, so that all other modules are enabled. But: the previous run enabled a module that I am not installing directly with role after changes. So my server state is still altered in a way that is different than the role is imposing itself.

My question is: should I take care of removing modules before I apply them so I always start from, let's say, fresh state?

E.g.:

- name: Remove modules
  file:
    dest: "/etc/filebeat/modules.d/{{ item }}"
    state: absent
  loop:
    - "module1.yml"
    - "module2.yml"
    - "module3.yml" # It was being installed in previous role, but not now

- name: Enable modules via 'modules.d' directory
  template:
    src: "modules.d/{{ item }}"
    dest: "/etc/filebeat/modules.d/{{ item }}"
    mode: '0644'
  loop:
    - "module1.yml"
    - "module2.yml"

So I remove module3.yml, because I remember that I've installed it before, and install module1.yml and module2.yml.

Instead of just installing what I need, no matter what has been installed before:

- name: Enable modules via 'modules.d' directory
  template:
    src: "modules.d/{{ item }}"
    dest: "/etc/filebeat/modules.d/{{ item }}"
    mode: '0644'
  loop:
    - "module1.yml"
    - "module2.yml"

Leaving me with module1.yml and module2.yml (desired) and, unfortunately: module3.yml (from previous role).

How to manage that to avoid such situations? And avoid treating server as one big stateful machine that even if I run a role, the output is different than desired, because something has been done before that I cannot see in current Ansible role code.

Do you code revert playbooks in your Ansible workflow to revert to initial state when needed?

I am curious. Thanks in advance for your reply.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无戏配角 2025-01-18 12:17:35

如果您想保证安全,请删除所有未列出的模块。

简短回答:查看该行下方示例中的“删除模块”块。

详细信息: 给定远程主机上用于测试的

shell> ssh admin@test_11 ls -1 /tmp/etc/filebeat/modules.d
module99.yml

目录 声明模块的路径以及要配置的模块列表

  fb_modules_path: /tmp/etc/filebeat/modules.d
  fb_modules:
    - module1.yml
    - module2.yml
    - module3.yml

创建模块的模板

tree> tree modules.d/
modules.d/
├── module1.yml.j2
├── module2.yml.j2
└── module3.yml.j2

并为单个远程主机创建模块 test_11在此示例中

    - name: Create modules
      template:
        src: "modules.d/{{ item }}.j2"
        dest: "{{ fb_modules_path }}/{{ item }}"
        mode: '0644'
      loop: "{{ fb_modules }}"
      notify: restart_filebeat
PLAY [test_11] *******************************************************************************

TASK [Create modules] ************************************************************************
changed: [test_11] => (item=module1.yml)
changed: [test_11] => (item=module2.yml)
changed: [test_11] => (item=module3.yml)

要删除列表中没有的所有模块 fb_modules 查找目录 fb_modules_path 中的所有文件 声明

        - name: Find all files in {{ fb_modules_path }}
          find:
            path: "{{ fb_modules_path }}"
          register: find_fb_modules

找到的模块列表以及应删除的模块列表删除

  fb_modules_found: "{{ find_fb_modules.files|map(attribute='path')|
                                              map('basename') }}"
  fb_modules_remove: "{{ fb_modules_found|difference(fb_modules) }}"

给予

  fb_modules_found: ['module99.yml', 'module1.yml', 'module3.yml', 'module2.yml']
  fb_modules_remove: ['module99.yml']

删除模块

        - name: Remove modules
          file:
            dest: "{{ fb_modules_path }}/{{ item }}"
            state: absent
          loop: "{{ fb_modules_remove }}"
          notify: restart_filebeat
TASK [Remove modules] ************************************************************************
changed: [test_11] => (item=module99.yml)

查看结果

shell> ssh admin@test_11 ls -1 /tmp/etc/filebeat/modules.d
module1.yml
module2.yml
module3.yml

用于测试的完整剧本示例

- hosts: test_11

  vars:

    fb_modules_path: /tmp/etc/filebeat/modules.d
    fb_modules:
      - module1.yml
      - module2.yml
      - module3.yml

    fb_modules_found: "{{ find_fb_modules.files|map(attribute='path')|
                                                map('basename') }}"
    fb_modules_remove: "{{ fb_modules_found|difference(fb_modules) }}"

  tasks:

    - name: Create modules
      template:
        src: "modules.d/{{ item }}.j2"
        dest: "{{ fb_modules_path }}/{{ item }}"
        mode: '0644'
      loop: "{{ fb_modules }}"
      notify: restart_filebeat

    - name: Remove modules
      block:
        - name: Find all files in {{ fb_modules_path }}
          find:
            path: "{{ fb_modules_path }}"
          register: find_fb_modules
        - debug:
            msg: |
              fb_modules_found: {{ fb_modules_found }}
              fb_modules_remove: {{ fb_modules_remove }}
          when: debug|d(false)|bool
        - name: Remove modules
          file:
            dest: "{{ fb_modules_path }}/{{ item }}"
            state: absent
          loop: "{{ fb_modules_remove }}"
          notify: restart_filebeat

  handlers:

    - name: Restart filebeat service
      listen: restart_filebeat
#     systemd:
#       name: filebeat
#       state: restarted
      debug:
        msg: Restart filebeat

Remove all modules not listed if you want to stay safe.

Short answer: Look at the block 'Remove modules' in the example below the line.

Details: Given the directory on the remote host for testing

shell> ssh admin@test_11 ls -1 /tmp/etc/filebeat/modules.d
module99.yml

Declare the path to the modules and the list of the modules you want to configure

  fb_modules_path: /tmp/etc/filebeat/modules.d
  fb_modules:
    - module1.yml
    - module2.yml
    - module3.yml

Create the templates for the modules

tree> tree modules.d/
modules.d/
├── module1.yml.j2
├── module2.yml.j2
└── module3.yml.j2

and create the modules for a single remote host test_11 in this example

    - name: Create modules
      template:
        src: "modules.d/{{ item }}.j2"
        dest: "{{ fb_modules_path }}/{{ item }}"
        mode: '0644'
      loop: "{{ fb_modules }}"
      notify: restart_filebeat
PLAY [test_11] *******************************************************************************

TASK [Create modules] ************************************************************************
changed: [test_11] => (item=module1.yml)
changed: [test_11] => (item=module2.yml)
changed: [test_11] => (item=module3.yml)

To remove all modules that are not in the list fb_modules find all files in the directory fb_modules_path

        - name: Find all files in {{ fb_modules_path }}
          find:
            path: "{{ fb_modules_path }}"
          register: find_fb_modules

Declare the list of found modules and the list of the modules that should be removed

  fb_modules_found: "{{ find_fb_modules.files|map(attribute='path')|
                                              map('basename') }}"
  fb_modules_remove: "{{ fb_modules_found|difference(fb_modules) }}"

give

  fb_modules_found: ['module99.yml', 'module1.yml', 'module3.yml', 'module2.yml']
  fb_modules_remove: ['module99.yml']

Remove the modules

        - name: Remove modules
          file:
            dest: "{{ fb_modules_path }}/{{ item }}"
            state: absent
          loop: "{{ fb_modules_remove }}"
          notify: restart_filebeat
TASK [Remove modules] ************************************************************************
changed: [test_11] => (item=module99.yml)

Take a look at the result

shell> ssh admin@test_11 ls -1 /tmp/etc/filebeat/modules.d
module1.yml
module2.yml
module3.yml

Example of a complete playbook for testing

- hosts: test_11

  vars:

    fb_modules_path: /tmp/etc/filebeat/modules.d
    fb_modules:
      - module1.yml
      - module2.yml
      - module3.yml

    fb_modules_found: "{{ find_fb_modules.files|map(attribute='path')|
                                                map('basename') }}"
    fb_modules_remove: "{{ fb_modules_found|difference(fb_modules) }}"

  tasks:

    - name: Create modules
      template:
        src: "modules.d/{{ item }}.j2"
        dest: "{{ fb_modules_path }}/{{ item }}"
        mode: '0644'
      loop: "{{ fb_modules }}"
      notify: restart_filebeat

    - name: Remove modules
      block:
        - name: Find all files in {{ fb_modules_path }}
          find:
            path: "{{ fb_modules_path }}"
          register: find_fb_modules
        - debug:
            msg: |
              fb_modules_found: {{ fb_modules_found }}
              fb_modules_remove: {{ fb_modules_remove }}
          when: debug|d(false)|bool
        - name: Remove modules
          file:
            dest: "{{ fb_modules_path }}/{{ item }}"
            state: absent
          loop: "{{ fb_modules_remove }}"
          notify: restart_filebeat

  handlers:

    - name: Restart filebeat service
      listen: restart_filebeat
#     systemd:
#       name: filebeat
#       state: restarted
      debug:
        msg: Restart filebeat

碍人泪离人颜 2025-01-18 12:17:35

简而言之:

- name: Configure filebeat modules
  hosts: all

  vars:
    fb_modules_d:
      - file: module1.yml
        state: present
      - file: module2.yml
        state: present
      - file: module3.yml
        state: absent

  tasks:
    - name: Make sure all needed module files are present
      template:
        src: "modules.d/{{ item.file }}"
        dest: "/etc/filebeat/modules.d/{{ item.file }}"
        mode: '0644'
      loop: "{{ fb_modules_d | selectattr('state', '==', 'present') }}"
      notifiy: restart_filebeat
 
    - name: Make sure all disabled modules are removed
      file:
        dest: "/etc/filebeat/modules.d/{{ item.file }}"
        state: "{{ item.state }}"
      loop: loop: "{{ fb_modules_d | selectattr('state', '==', 'absent') }}"
      notify: restart_filebeat

  handlers:
    - name: Restart filebeat service
      listen: restart_filebeat
      systemd:
        name: filebeat
        state: restarted

注意:我在示例的剧本中声明了该变量,但该变量很可能应该进入您的库存(组或主机级别),并且肯定不是在某个角色中(除了文档的默认值)

In a nutshell:

- name: Configure filebeat modules
  hosts: all

  vars:
    fb_modules_d:
      - file: module1.yml
        state: present
      - file: module2.yml
        state: present
      - file: module3.yml
        state: absent

  tasks:
    - name: Make sure all needed module files are present
      template:
        src: "modules.d/{{ item.file }}"
        dest: "/etc/filebeat/modules.d/{{ item.file }}"
        mode: '0644'
      loop: "{{ fb_modules_d | selectattr('state', '==', 'present') }}"
      notifiy: restart_filebeat
 
    - name: Make sure all disabled modules are removed
      file:
        dest: "/etc/filebeat/modules.d/{{ item.file }}"
        state: "{{ item.state }}"
      loop: loop: "{{ fb_modules_d | selectattr('state', '==', 'absent') }}"
      notify: restart_filebeat

  handlers:
    - name: Restart filebeat service
      listen: restart_filebeat
      systemd:
        name: filebeat
        state: restarted

Note: I declared the variable inside the playbook for the example but that one one should most probably go inside your inventory (group or host level), and certainly not in a role (except in defaults for documentation)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文