集中定义冗余任务选项并在不同任务中重用它们

问题描述 投票:0回答:2

是否可以集中定义任务选项以在不同任务中重用它们?

我目前正在使用几个 community.postgresql 模块,例如

postgresql_db
postgresql_user
postgresql_privs
。我总是必须定义选项
login_host
port
login_user
login_password
,但这些在整个执行过程中都是相同的,所以我想集中定义它们一次,然后只包含每个选项。

到目前为止,我的任务看起来像这样:

- name: Create database
  community.postgresql.postgresql_db:
    name: "{{ pg_db_name }}"

    login_host: "{{ pg_host }}"
    port: "{{ pg_port }}"
    login_user: "{{ pg_admin.username }}"
    login_password: "{{ pg_admin.password }}"

- name: Create database user
  community.postgresql.postgresql_user:
    name: "{{ pg_user.username }}"
    password: "{{ pg_user.password }}"

    login_host: "{{ pg_host }}"
    port: "{{ pg_port }}"
    login_user: "{{ pg_admin.username }}"
    login_password: "{{ pg_admin.password }}"

- name: Set user privileges on database
  community.postgresql.postgresql_privs:
    database: "{{ pg_db_name }}"
    roles: "{{ pg_user.username }}"
    privs: ALL
    type: database

    login_host: "{{ pg_host }}"
    port: "{{ pg_port }}"
    login_user: "{{ pg_admin.username }}"
    login_password: "{{ pg_admin.password }}"

我以为我可以通过 YAML Merge 实现整个事情,不幸的是这似乎不起作用,我总是收到以下错误消息:

错误!冲突的操作语句:login_host、login_user

我尝试使用 YAML Merge 实现它,如下所示:

- &pg_connect {
    login_host: "{{ pg_host }}",
    port: "{{ pg_port }}",
    login_user: "{{ pg_admin.username }}",
    login_password: "{{ pg_admin.password }}"
  }

- name: Create database
  community.postgresql.postgresql_db:
    << : *pg_connect
    name: "{{ pg_db_name }}"


- name: Create database user
  community.postgresql.postgresql_user:
    << : *pg_connect
    name: "{{ pg_user.username }}"
    password: "{{ pg_user.password }}"

- name: Set user privileges on database
  community.postgresql.postgresql_privs:
    << : *pg_connect
    database: "{{ pg_db_name }}"
    roles: "{{ pg_user.username }}"
    privs: ALL
    type: database

Ansible 中是否有一个(简单的)解决方案来保存这些冗余行?


我现在已经使用

module_defaults
变体进行了一段时间的测试,但遇到了以下问题。

我用最小的剧本进行了测试,以尽可能避免副作用。

  • pg_connect_modules
    定义在剧本的
    vars
    区域(如示例)中作为静态定义进行测试,并在运行时通过
    set_fact
  • 在所有测试场景中,
  • pg_connect
    在运行时通过
    set_fact
    定义。
  • module_defaults
    任务定义创建数据库No 1工作没有问题。
  • 任务
    创建数据库No 2
    module_defaults定义总是会导致以下错误 - 根本无法启动playbook执行,错误直接出现。

    ansible-playbook -i inventory play.yml

    错误!字段“module_defaults”应该是一个字典或字典列表,其键必须是静态操作、模块或组名称。只有值可以包含模板。例如:{'ping': "{{ ping_defaults }}"}

  • 只有注释掉任务 创建数据库 No 2 或至少该任务的
    module_defaults
    行,我才能启动剧本执行。
  • 如果我在任务文件中包含数据库任务并且通过
    include_tasks
    包含它们,则包含失败;剧本执行到该点,然后包含失败并出现相同的错误。

我的剧本是这样的:

play.yml
---

- hosts: testserver
  become: yes

  vars:
    pg_connect_modules:
      community.postgresql.postgresql_db:
        login_host: "localhost"
        port: "5432"
        login_user: "postgres_admin"
        login_password: "myPass"

  tasks:
    - set_fact:
        pg_connect: "{{ common_defaults }}"
      vars:
        common_defaults:
          login_host: "localhost"
          port: "5432"
          login_user: "postgres_admin"
          login_password: "myPass"

    - name: Create database No 1
      community.postgresql.postgresql_db:
        name: "test1"
      module_defaults:
        community.postgresql.postgresql_db: "{{ pg_connect }}"

    - name: Create database No 2
      community.postgresql.postgresql_db:
        name: "test1"
      module_defaults: "{{ pg_connect_modules }}"
ansible yaml
2个回答
7
投票

更新:


A:在任何级别(游戏、角色、区块、任务),您都可以使用module_defaults。例如,在一个块中

- block:

    - name: Create database
      community.postgresql.postgresql_db:
        name: "{{ pg_db_name }}"

    - name: Create database user
      community.postgresql.postgresql_user:
        name: "{{ pg_user.username }}"
        password: "{{ pg_user.password }}"

    - name: Set user privileges on database
      community.postgresql.postgresql_privs:
        database: "{{ pg_db_name }}"
        roles: "{{ pg_user.username }}"
        privs: ALL
        type: database

  module_defaults:
    community.postgresql.postgresql_db:
      login_host: "{{ pg_host }}"
      port: "{{ pg_port }}"
      login_user: "{{ pg_admin.username }}"
      login_password: "{{ pg_admin.password }}"
    community.postgresql.postgresql_user:
      login_host: "{{ pg_host }}"
      port: "{{ pg_port }}"
      login_user: "{{ pg_admin.username }}"
      login_password: "{{ pg_admin.password }}"
    community.postgresql.postgresql_privs:
      login_host: "{{ pg_host }}"
      port: "{{ pg_port }}"
      login_user: "{{ pg_admin.username }}"
      login_password: "{{ pg_admin.password }}"

在代码外部组合并声明字典module_defaults是很实用的。例如,在 group_vars

shell> cat group_vars/all/my_defaults.yml
my_module_defaults_list:
  - modules:
      - community.postgresql.postgresql_db
      - community.postgresql.postgresql_user
      - community.postgresql.postgresql_privs
    defaults:
      login_host: "{{ pg_host }}"
      port: "{{ pg_port }}"
      login_user: "{{ pg_admin.username }}"
      login_password: "{{ pg_admin.password }}"

my_module_defaults_str: |
  {% for i in my_module_defaults_list %}
  {{ dict(i.modules|product([i.defaults])) }}
  {% endfor %}
my_module_defaults: "{{ my_module_defaults_str|from_yaml }}"

给定以下变量

  pg_host: pb.example.com
  pg_port: 5432
  pg_admin:
    username: admin
    password: admin_passwd

字典给出

  my_module_defaults:
    community.postgresql.postgresql_db:
      login_host: pb.example.com
      login_password: admin_passwd
      login_user: admin
      port: 5432
    community.postgresql.postgresql_privs:
      login_host: pb.example.com
      login_password: admin_passwd
      login_user: admin
      port: 5432
    community.postgresql.postgresql_user:
      login_host: pb.example.com
      login_password: admin_passwd
      login_user: admin
      port: 5432

不幸的是,无法直接在戏剧中使用它。由于某种原因,字典的键必须是静态的

- block:

    - name: Create database
      community.postgresql.postgresql_db:
        name: "{{ pg_db_name }}"

    - name: Create database user
      community.postgresql.postgresql_user:
        name: "{{ pg_user.username }}"
        password: "{{ pg_user.password }}"

    - name: Set user privileges on database
      community.postgresql.postgresql_privs:
        database: "{{ pg_db_name }}"
        roles: "{{ pg_user.username }}"
        privs: ALL
        type: database

  module_defaults: "{{ my_module_defaults }}"

上面的代码会导致错误:

错误!字段“module_defaults”应该是一个字典或字典列表,其键必须是静态操作、模块或组名称。只有值可以包含模板。例如:{'ping': "{{ ping_defaults }}"}

作为解决方法,您可以创建以下模板

shell> cat postgresql.yml.j2
- block:

    - name: Create database
      community.postgresql.postgresql_db:
        name: "{{ pg_db_name }}"

    - name: Create database user
      community.postgresql.postgresql_user:
        name: "{{ pg_user.username }}"
        password: "{{ pg_user.password }}"

    - name: Set user privileges on database
      community.postgresql.postgresql_privs:
        database: "{{ pg_db_name }}"
        roles: "{{ pg_user.username }}"
        privs: ALL
        type: database

  module_defaults:
{{ my_module_defaults|to_nice_yaml(indent=2)|indent(4, first=true) }}

并将创建的文件包含在播放中

    - template:
        src: postgresql.yml.j2
        dest: "{{ playbook_dir }}/postgresql.yml"
      delegate_to: localhost
      run_once: true
      tags: build
    - include_tasks: postgresql.yml

shell> cat postgresql.yml
- block:

    - name: Create database
      community.postgresql.postgresql_db:
        name: "db_01"

    - name: Create database user
      community.postgresql.postgresql_user:
        name: "user"
        password: "user_passwd"

    - name: Set user privileges on database
      community.postgresql.postgresql_privs:
        database: "db_01"
        roles: "user"
        privs: ALL
        type: database

  module_defaults:
    community.postgresql.postgresql_db:
      login_host: pb.example.com
      login_password: admin_passwd
      login_user: admin
      port: 5432
    community.postgresql.postgresql_privs:
      login_host: pb.example.com
      login_password: admin_passwd
      login_user: admin
      port: 5432
    community.postgresql.postgresql_user:
      login_host: pb.example.com
      login_password: admin_passwd
      login_user: admin
      port: 5432

正确的解决方案是创建模块默认组source atm 中没有声明任何团体。你可以创建它。例如,找出您收藏的路径并创建组

shell> cat ~/.local/lib/python3.9/site-packages/ansible_collections/community/postgresql/meta/runtime.yml 
---
requires_ansible: '>=2.9.10'
action_groups:
  postgresql:
    - postgresql_db
    - postgresql_privs
    - postgresql_user

那么下面的块应该按预期工作

    - block:

        - name: Create database
          community.postgresql.postgresql_db:
            name: "db_01"

        - name: Create database user
          community.postgresql.postgresql_user:
            name: "user"
            password: "user_passwd"

        - name: Set user privileges on database
          community.postgresql.postgresql_privs:
            database: "db_01"
            roles: "user"
            privs: ALL
            type: database

      module_defaults:
        group/community.postgresql.postgresql:
          login_host: pb.example.com
          login_password: admin_passwd
          login_user: admin
          port: 5432

如果需要,您可以打开请求。有必要检查所有 postgresql 模块的所有参数的一致性并创建组。


备注:

  • 在关键任务环境中,在有限范围内提供login_password。请参阅 Ansible 将保管库密码文件传递到 playbook

  • 如果您想在游戏级别使用module_defaults,则字典必须在此范围内可用。请参阅 Ansible、module_defaults 和包模块(已过时;在 2.12 中已损坏)。

  • 引用CHANGELOG-v2.12.rst重大更改:“module_defaults中的操作、模块和组名称必须是静态值。它们的值仍然可以是模板。”

用于测试错误和解决方法的完整剧本示例

shell> cat pb3.yml
- hosts: localhost

  vars:

    my_module_defaults:
      debug:
        msg: common default

    debug_defaults:
      msg: common default

  tasks:

    - name: Work as expected
      debug:
      module_defaults:
        debug: "{{ debug_defaults }}"
      
#    - name: ERROR
#      debug:
#      module_defaults: "{{ my_module_defaults }}"
#
# ERROR! The field 'module_defaults' is supposed to be a dictionary or
# list of dictionaries, the keys of which must be static action, module,
# or group names. Only the values may contain templates. For example:
# {'ping': "{{ ping_defaults }}"}

    - name: Workaround
      template:
        src: my_module.yml.j2
        dest: "{{ playbook_dir }}/my_module.yml"
    - include_tasks: my_module.yml
shell> cat my_module.yml.j2
- block:

    - debug:

  module_defaults:
{{ my_module_defaults|to_nice_yaml(indent=2)|indent(4, first=true) }}
shell> cat my_module.yml
- block:

    - debug:

  module_defaults:
    debug:
      msg: common default

1
投票

您可以使用

set_fact
任务来定义 YAML 锚点:

- name: Registering common settings for Postgres tasks 
  set_fact:
    pg_connect: &pg_connect
      login_host: "{{ pg_host }}"
      port: "{{ pg_port }}"
      login_user: "{{ pg_admin.username }}"
      login_password: "{{ pg_admin.password }}"

然后像您尝试过的那样使用覆盖:

- name: Create database
  community.postgresql.postgresql_db:
    <<: *pg_connect
    name: "{{ pg_db_name }}"
© www.soinside.com 2019 - 2024. All rights reserved.