是否可以集中定义任务选项以在不同任务中重用它们?
我目前正在使用几个 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 }}"}
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 }}"
更新:
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
您可以使用
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 }}"